diff --git a/CHANGELOG.md b/CHANGELOG.md index 2908a60c..888e9717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,90 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.5.0] - 2026-07-28 + +### Added + +- OAR022 - OrderbyParameterCheck - Added `single-resource` test cases (v2, v3, v31, v32) verifying that paths ending with a path parameter (e.g. `/examples/{id}`) are correctly excluded by `applyToParameterizedPaths = false`. +- OAR025 - LimitParameterCheck - Added `single-resource` test cases (v2, v3, v31, v32) verifying that paths ending with a path parameter (e.g. `/examples/{id}`) are correctly excluded by `applyToParameterizedPaths = false`. +- OAR031 - ExamplesCheck - Per-level configuration via rule parameters `validate-response`, `validate-request-body`, `validate-parameter` and `validate-property` (all `true` by default); each level can be disabled independently. + +### Fixed + +- OAR017 - ResourcePathCheck - Added `delete` to the `exclude_patterns` default (now `get,me,search,delete`); paths ending with `/delete` (e.g. `/orders/delete`, `/orders/{orderId}/delete`) are now treated as pseudo-parameters and no longer trigger the alternation rule. +- OAR020 - ExpandParameterCheck - Fixed `verifyInV2PathEndingWithParam` test method that was incorrectly calling `verifyV3("with-param")` instead of `verifyV2("with-param")`; the Swagger 2.0 `with-param` test fixtures are now correctly exercised in v2 mode. +- OAR021 - ExcludeParameterCheck - Fixed `verifyInV2PathEndingWithParam` test, now correctly calls `verifyV2("with-param")`. +- OAR044 - MediaTypeCheck - Fixed `MEDIA_RANGE_PATTERN` to allow `*/*` (full wildcard) as a valid OAP3 media range; the type component now accepts `*` in addition to RFC 6838 type names. Added test coverage for vendor-specific types (`application/vnd.ms-excel`, `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`, `application/ld+json`, `application/vnd.github+json`). +- OAR004 - ValidWso2ScopesRoles - Fixed a field-shadowing bug in the shared base class that made the `pattern` parameter have no effect. +- OAR014 - ResourceLevelWithinNonSuggestedRange - `matchLevel` ignored `maxLevel` entirely; the parameter is now applied. +- OAR019 - SelectParameterCheck - Added real support for `paths` and `pathValidationStrategy`, and re-added the `parameterName` parameter (removed in an earlier refactor). +- OAR020 - ExpandParameterCheck - Removed hardcoded path-exclusion logic that bypassed the configurable `paths` parameter; re-added `parameterName`. +- OAR021 - ExcludeParameterCheck - Removed hardcoded path-exclusion logic that bypassed the configurable `paths` parameter; re-added `parameterName`. +- OAR038 - StandardCreateResponse - The `dataNode` parameter was never read; the check always used its default value instead. +- OAR040 - StandardWso2ScopesName - Fixed the same field-shadowing bug as OAR004. +- OAR082 - BinaryOrByteFormat - `fields-to-apply` was read before Sonar injected its configured value, so the parameter had no effect. +- OAR085 - OpenAPIVersion - `valid-versions` was read before Sonar injected its configured value, so the parameter had no effect. + +### Changed + +- OAR019, OAR020, OAR021 - `paths` now takes plain path segments (e.g. `/status`) instead of a regular expression. Default excluded paths (`/me`, `/health`, `/ping`, `/status`) are now matched as real path segments instead of a loose substring, so a path like `/subscription-status-reports` is no longer wrongly excluded. +- OAR037 - StringFormatCheck - Reclassified as a security rule (`VULNERABILITY`, tag `safety`, keeping its existing `format` rule group/package). String schemas must now declare a valid `format`, or — when no `format` is declared — a non-empty, syntactically valid `pattern`; schemas with neither a valid `format` nor a valid `pattern` are reported. +- OAR037 - StringFormatCheck - Rule no longer fires when a string schema omits the `format` field entirely; it only fires when `format` is present but not a recognized value. +- OAR031 - ExamplesCheck - Examples are now validated as four **independent** levels (response, request body, parameter, property). The response/request-body/parameter levels require an example declared at the media-type or schema **root** (non-recursive); examples nested inside schema properties no longer satisfy them. Aligns OAR031 with the Spectral ruleset (identical findings on the same document) and is stricter than before, so existing specs may surface new findings. + +## [1.5.0-beta-4] - 2026-07-14 + +### Fixed + +- OAR004 - ValidWso2ScopesRoles - Fixed a field-shadowing bug in the shared base class that made the `pattern` parameter have no effect. +- OAR014 - ResourceLevelWithinNonSuggestedRange - `matchLevel` ignored `maxLevel` entirely; the parameter is now applied. +- OAR019 - SelectParameterCheck - Added real support for `paths` and `pathValidationStrategy`, and re-added the `parameterName` parameter (removed in an earlier refactor). +- OAR020 - ExpandParameterCheck - Removed hardcoded path-exclusion logic that bypassed the configurable `paths` parameter; re-added `parameterName`. +- OAR021 - ExcludeParameterCheck - Removed hardcoded path-exclusion logic that bypassed the configurable `paths` parameter; re-added `parameterName`. +- OAR038 - StandardCreateResponse - The `dataNode` parameter was never read; the check always used its default value instead. +- OAR040 - StandardWso2ScopesName - Fixed the same field-shadowing bug as OAR004. +- OAR082 - BinaryOrByteFormat - `fields-to-apply` was read before Sonar injected its configured value, so the parameter had no effect. +- OAR085 - OpenAPIVersion - `valid-versions` was read before Sonar injected its configured value, so the parameter had no effect. + +### Changed + +- OAR019, OAR020, OAR021 - `paths` now takes plain path segments (e.g. `/status`) instead of a regular expression. Default excluded paths (`/me`, `/health`, `/ping`, `/status`) are now matched as real path segments instead of a loose substring, so a path like `/subscription-status-reports` is no longer wrongly excluded. + +## [1.5.0-beta-3] - 2026-07-08 + +### Changed + +- OAR037 - StringFormatCheck - Reclassified as a security rule (`VULNERABILITY`, tag `safety`, keeping its existing `format` rule group/package). String schemas must now declare a valid `format`, or — when no `format` is declared — a non-empty, syntactically valid `pattern`; schemas with neither a valid `format` nor a valid `pattern` are reported. + +## [1.5.0-beta-2] - 2026-06-24 + +### Changed + +- OAR037 - StringFormatCheck - Rule no longer fires when a string schema omits the `format` field entirely; it only fires when `format` is present but not a recognized value. + +### Fixed + +- OAR017 - ResourcePathCheck - Added `delete` to the `exclude_patterns` default (now `get,me,search,delete`); paths ending with `/delete` (e.g. `/orders/delete`, `/orders/{orderId}/delete`) are now treated as pseudo-parameters and no longer trigger the alternation rule. +- OAR020 - ExpandParameterCheck - Fixed `verifyInV2PathEndingWithParam` test method that was incorrectly calling `verifyV3("with-param")` instead of `verifyV2("with-param")`; the Swagger 2.0 `with-param` test fixtures are now correctly exercised in v2 mode. +- OAR021 - ExcludeParameterCheck - Fixed `verifyInV2PathEndingWithParam` test, now correctly calls `verifyV2("with-param")`. +- OAR044 - MediaTypeCheck - Fixed `MEDIA_RANGE_PATTERN` to allow `*/*` (full wildcard) as a valid OAP3 media range; the type component now accepts `*` in addition to RFC 6838 type names. Added test coverage for vendor-specific types (`application/vnd.ms-excel`, `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`, `application/ld+json`, `application/vnd.github+json`). + +### Added + +- OAR022 - OrderbyParameterCheck - Added `single-resource` test cases (v2, v3, v31, v32) verifying that paths ending with a path parameter (e.g. `/examples/{id}`) are correctly excluded by `applyToParameterizedPaths = false`. +- OAR025 - LimitParameterCheck - Added `single-resource` test cases (v2, v3, v31, v32) verifying that paths ending with a path parameter (e.g. `/examples/{id}`) are correctly excluded by `applyToParameterizedPaths = false`. + +## [1.5.0-beta-1] - 2026-06-15 + +### Added + +- OAR031 - ExamplesCheck - Per-level configuration via rule parameters `validate-response`, `validate-request-body`, `validate-parameter` and `validate-property` (all `true` by default); each level can be disabled independently. + +### Changed + +- OAR031 - ExamplesCheck - Examples are now validated as four **independent** levels (response, request body, parameter, property). The response/request-body/parameter levels require an example declared at the media-type or schema **root** (non-recursive); examples nested inside schema properties no longer satisfy them. Aligns OAR031 with the Spectral ruleset (identical findings on the same document) and is stricter than before, so existing specs may surface new findings. + + ## [1.4.1] - 2026-06-04 ### Added diff --git a/pom.xml b/pom.xml index 264be0bf..55865267 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.apiaddicts.apitools.dosonarapi sonaropenapi-rules-community - 1.4.1 + 1.5.0 sonar-plugin SonarQube OpenAPI Community Rules diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/AbstractPatternWso2ScopesCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/AbstractPatternWso2ScopesCheck.java index fb482421..8e5fb60e 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/AbstractPatternWso2ScopesCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/AbstractPatternWso2ScopesCheck.java @@ -13,7 +13,6 @@ public abstract class AbstractPatternWso2ScopesCheck extends AbstractWso2ScopesC protected final String defaultPatternValue; protected Pattern pattern; - private String patternStr; protected AbstractPatternWso2ScopesCheck(String key, String message, String fieldName, String defaultPatternValue) { this.ruleKey = key; @@ -22,8 +21,11 @@ protected AbstractPatternWso2ScopesCheck(String key, String message, String fiel this.defaultPatternValue = defaultPatternValue; } + protected abstract String getPatternStr(); + @Override protected void visitFile(JsonNode root) { + String patternStr = getPatternStr(); pattern = Pattern.compile(patternStr != null ? patternStr : defaultPatternValue); } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR004ValidWso2ScopesRolesCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR004ValidWso2ScopesRolesCheck.java index 7cb8c273..8e520b51 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR004ValidWso2ScopesRolesCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR004ValidWso2ScopesRolesCheck.java @@ -19,4 +19,9 @@ public class OAR004ValidWso2ScopesRolesCheck extends AbstractPatternWso2ScopesCh public OAR004ValidWso2ScopesRolesCheck() { super(KEY, MESSAGE, "roles", DEFAULT_PATTERN_VALUE); } + + @Override + protected String getPatternStr() { + return patternStr; + } } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR040StandardWso2ScopesNameCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR040StandardWso2ScopesNameCheck.java index bd67e0b1..ee3bd39b 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR040StandardWso2ScopesNameCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/apim/wso2/OAR040StandardWso2ScopesNameCheck.java @@ -19,4 +19,9 @@ public class OAR040StandardWso2ScopesNameCheck extends AbstractPatternWso2Scopes public OAR040StandardWso2ScopesNameCheck() { super(KEY, MESSAGE, "name", DEFAULT_PATTERN_VALUE); } + + @Override + protected String getPatternStr() { + return patternStr; + } } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheck.java index e63b1aed..d174a7f0 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheck.java @@ -15,6 +15,7 @@ import org.apiaddicts.apitools.dosonarapi.api.v32.OpenApi32Grammar; import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR031ExamplesCheck.KEY) public class OAR031ExamplesCheck extends BaseCheck { @@ -27,6 +28,39 @@ public class OAR031ExamplesCheck extends BaseCheck { private static final String ITEMS = "items"; private static final String ERROR_RESPONSE = "OAR031.error-response"; + private static final String ERROR_REQUEST = "OAR031.error-request"; + + @RuleProperty( + key = "validateResponse", + description = "Validate that responses declare a body-level example", + defaultValue = "true", + type = "BOOLEAN" + ) + private boolean validateResponse = true; + + @RuleProperty( + key = "validateRequestBody", + description = "Validate that request bodies declare a body-level example", + defaultValue = "true", + type = "BOOLEAN" + ) + private boolean validateRequestBody = true; + + @RuleProperty( + key = "validateParameter", + description = "Validate that parameters declare an example", + defaultValue = "true", + type = "BOOLEAN" + ) + private boolean validateParameter = true; + + @RuleProperty( + key = "validateProperty", + description = "Validate that each schema property declares an example", + defaultValue = "true", + type = "BOOLEAN" + ) + private boolean validateProperty = true; private final ExternalRefHandler handleExternalRef = new ExternalRefHandler(); @@ -67,11 +101,13 @@ private void visitParameterNode(JsonNode node) { JsonNode schema = resolved.get(SCHEMA); + // Parameter level: the parameter itself, or its schema's ROOT, must declare an + // example. Examples buried inside schema properties do NOT satisfy this level. boolean hasExample = !resolved.get(EXAMPLE).isMissing() || !resolved.get(EXAMPLES).isMissing() - || (!schema.isMissing() && isSchemaCovered(schema)); + || schemaHasRootExample(schema); - if (!hasExample) { + if (validateParameter && !hasExample) { addIssue(KEY, translate("OAR031.error-parameter"), handleExternalRef.getTrueNode(node)); } }); @@ -89,10 +125,11 @@ private void visitV2Node(JsonNode node) { private void visitResponseV2Node(JsonNode node) { handleExternalRef.resolve(node, resolved -> { JsonNode schemaNode = resolved.get(SCHEMA); + // Response level: a response-level examples map or the schema ROOT example. boolean hasExample = !resolved.get(EXAMPLES).isMissing() - || (!schemaNode.isMissing() && isSchemaCovered(schemaNode)); + || schemaHasRootExample(schemaNode); - if (!hasExample) { + if (validateResponse && !hasExample) { addIssue(KEY, translate(ERROR_RESPONSE), handleExternalRef.getTrueNode(node.key())); } }); @@ -117,26 +154,42 @@ private void processResponses(JsonNode node, java.util.function.Consumer + !resolved.get(EXAMPLE).isMissing() || !resolved.get(EXAMPLES).isMissing()); + } + + // Recursive coverage, used only by the property-level walk. private boolean isSchemaCovered(JsonNode schemaNode) { if (schemaNode.isMissing()) return false; @@ -160,6 +213,8 @@ private boolean isSchemaCovered(JsonNode schemaNode) { } private void visitSchemaNode(JsonNode node) { + if (!validateProperty) return; + JsonNode parentNode = (JsonNode) node.getParent().getParent(); if (parentNode.getType().equals(OpenApi3Grammar.PARAMETER) || parentNode.getType().equals(OpenApi31Grammar.PARAMETER) || parentNode.getType().equals(OpenApi32Grammar.PARAMETER)) { @@ -185,6 +240,8 @@ private void visitSchemaNode(JsonNode node) { } private void visitPathNode(JsonNode node) { + if (!validateProperty) return; + node.properties().stream() .filter(prop -> isOperation(prop)) .map(JsonNode::value) @@ -223,4 +280,4 @@ private void visitSchemaNode2(JsonNode responseNode) { }); }); } -} \ No newline at end of file +} diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/format/AbstractFormatCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/format/AbstractFormatCheck.java index 5d4d728b..adb15cde 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/format/AbstractFormatCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/format/AbstractFormatCheck.java @@ -28,13 +28,13 @@ private void visitV2Node(JsonNode node) { String type = typeNode.getTokenValue(); JsonNode formatNode = node.get("format"); if (formatNode.isMissing()) { - validate(type, null, typeNode); + validate(type, null, typeNode, node); return; } String format = formatNode.getTokenValue(); if (format == null || format.isBlank()) return; - validate(type, format.trim(), typeNode); + validate(type, format.trim(), typeNode, node); } - public abstract void validate(String type, String format, JsonNode typeNode); + public abstract void validate(String type, String format, JsonNode typeNode, JsonNode node); } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR016NumericFormatCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR016NumericFormatCheck.java index 4a0e417a..01ec200a 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR016NumericFormatCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR016NumericFormatCheck.java @@ -10,7 +10,7 @@ public class OAR016NumericFormatCheck extends AbstractFormatCheck { private static final String MESSAGE = "OAR016.error"; @Override - public void validate(String type, String format, JsonNode typeNode) { + public void validate(String type, String format, JsonNode typeNode, JsonNode node) { if (isInvalidInteger(type, format) || isInvalidNumber(type, format)) { addIssue(KEY, translate(MESSAGE), typeNode.key()); } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheck.java index 72ebeaeb..96e58d22 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheck.java @@ -4,6 +4,8 @@ import org.sonar.check.RuleProperty; import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode; import java.util.Set; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -22,17 +24,44 @@ public class OAR037StringFormatCheck extends AbstractFormatCheck { private String formatsAllowed = DEFAULT_FORMATS_ALLOWED; @Override - public void validate(String type, String format, JsonNode typeNode) { - Set validFormats = Stream.of(formatsAllowed.split(",")) - .map(f -> f.trim().toLowerCase()) - .collect(Collectors.toSet()); + public void validate(String type, String format, JsonNode typeNode, JsonNode node) { + if (!"string".equals(type)) { + return; + } + + if (format != null) { + Set validFormats = Stream.of(formatsAllowed.split(",")) + .map(f -> f.trim().toLowerCase()) + .collect(Collectors.toSet()); + if (!validFormats.contains(format.toLowerCase())) { + addIssue(KEY, translate(MESSAGE), typeNode.key()); + } + return; + } - if (isInvalidString(type, format, validFormats)) { + if (!hasValidPattern(node)) { addIssue(KEY, translate(MESSAGE), typeNode.key()); } } - private boolean isInvalidString(String type, String format, Set validFormats) { - return "string".equals(type) && (format == null || !validFormats.contains(format.toLowerCase())); + private boolean hasValidPattern(JsonNode node) { + JsonNode patternNode = node.get("pattern"); + if (patternNode.isMissing()) { + return false; + } + String pattern = patternNode.getTokenValue(); + if (pattern == null || pattern.isBlank()) { + return false; + } + return isValidRegex(pattern.trim()); + } + + private boolean isValidRegex(String pattern) { + try { + Pattern.compile(pattern); + return true; + } catch (PatternSyntaxException e) { + return false; + } } -} \ No newline at end of file +} diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java index aa7992ef..15d3a523 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java @@ -52,7 +52,7 @@ public class OAR044MediaTypeCheck extends BaseCheck { ); @VisibleForTesting static final Pattern MEDIA_RANGE_PATTERN = Pattern.compile( - "[a-zA-Z0-9.][a-zA-Z0-9.!#$&_^+\\-]+/" + + "(\\*|[a-zA-Z0-9.][a-zA-Z0-9.!#$&_^+\\-]+)/" + "(\\*|" + "[a-zA-Z0-9.][a-zA-Z0-9.!#$&_^+\\-]+" + "(; charset=[a-zA-Z0-9_\\-]+)?" + diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR052UndefinedNumericFormatCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR052UndefinedNumericFormatCheck.java index 38b4006f..52a84979 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR052UndefinedNumericFormatCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR052UndefinedNumericFormatCheck.java @@ -10,7 +10,7 @@ public class OAR052UndefinedNumericFormatCheck extends AbstractFormatCheck { private static final String MESSAGE = "OAR052.error"; @Override - public void validate(String type, String format, JsonNode typeNode) { + public void validate(String type, String format, JsonNode typeNode, JsonNode node) { if (("integer".equals(type) || "number".equals(type)) && format == null) { addIssue(KEY, translate(MESSAGE), typeNode.key()); } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR014ResourceLevelWithinNonSuggestedRangeCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR014ResourceLevelWithinNonSuggestedRangeCheck.java index 75164014..504aabe0 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR014ResourceLevelWithinNonSuggestedRangeCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR014ResourceLevelWithinNonSuggestedRangeCheck.java @@ -32,6 +32,6 @@ public OAR014ResourceLevelWithinNonSuggestedRangeCheck() { @Override boolean matchLevel(long level) { - return minLevel <= level; + return minLevel <= level && level <= maxLevel; } } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheck.java index 41796f8e..28518cda 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheck.java @@ -20,7 +20,7 @@ public class OAR017ResourcePathCheck extends BaseCheck { public static final String KEY = "OAR017"; private static final String MESSAGE = "OAR017.error"; - public static final String EXCLUDE_PATTERNS = "get,me,search"; + public static final String EXCLUDE_PATTERNS = "get,me,search,delete"; @RuleProperty( key = "exclude_patterns", diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR038StandardCreateResponseCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR038StandardCreateResponseCheck.java index 6cfaa928..57e27ce6 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR038StandardCreateResponseCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/operations/OAR038StandardCreateResponseCheck.java @@ -24,7 +24,6 @@ public class OAR038StandardCreateResponseCheck extends AbstractExplicitResponseC description = "Valid top-level property name for the standard response.", defaultValue = DATA_PROPERTY ) - @SuppressWarnings("unused") private String dataNode = DATA_PROPERTY; public OAR038StandardCreateResponseCheck() { @@ -44,7 +43,7 @@ protected void visitV2ExplicitNode(JsonNode node) { for (Map.Entry entry : properties.entrySet()) { String propName = entry.getKey(); - if (DATA_PROPERTY.equals(propName) || ERROR_PROPERTY.equals(propName)) { + if (dataNode.equals(propName) || ERROR_PROPERTY.equals(propName)) { Map subProps = getAllProperties(resolve(entry.getValue())); if (subProps.isEmpty()) { addIssue(KEY, translate("OAR038.error-required-one-property"), entry.getValue().key()); diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractCollectionQueryParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractCollectionQueryParameterCheck.java index 0eef8f02..ab9c31dc 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractCollectionQueryParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractCollectionQueryParameterCheck.java @@ -1,30 +1,13 @@ package apiaddicts.sonar.openapi.checks.parameters; -import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode; - public abstract class AbstractCollectionQueryParameterCheck extends AbstractQueryParameterCheck { protected AbstractCollectionQueryParameterCheck( String ruleKey, String messageKey, - String parameterName, + String defaultParameterName, boolean applyToParameterizedPaths ) { - super(ruleKey, messageKey, parameterName, applyToParameterizedPaths); - } - - @Override - public void visitNode(JsonNode node) { - if (!"get".equals(node.key().getTokenValue())) return; - - String path = getPath(node); - - if (endsWithPathParam(path)) return; - if (path.contains("/me/") || path.endsWith("/me")) return; - if (path.contains("status") || path.contains("health") || path.contains("ping")) return; - - if (!hasParameterInNode(node)) { - addIssue(ruleKey, translate(messageKey, parameterName), node.key()); - } + super(ruleKey, messageKey, defaultParameterName, applyToParameterizedPaths); } } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractQueryParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractQueryParameterCheck.java index c5f31e28..7d4fb2d4 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractQueryParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/AbstractQueryParameterCheck.java @@ -4,59 +4,54 @@ import com.google.common.collect.ImmutableSet; import com.sonar.sslr.api.AstNode; import com.sonar.sslr.api.AstNodeType; +import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; +import java.util.List; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apiaddicts.apitools.dosonarapi.api.v2.OpenApi2Grammar; import org.apiaddicts.apitools.dosonarapi.api.v3.OpenApi3Grammar; import org.apiaddicts.apitools.dosonarapi.api.v31.OpenApi31Grammar; import org.apiaddicts.apitools.dosonarapi.api.v32.OpenApi32Grammar; import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode; -import org.sonar.check.RuleProperty; public abstract class AbstractQueryParameterCheck extends BaseCheck { protected static final String DEFAULT_PATH = "/examples"; protected static final String PATH_STRATEGY = "/include"; - private static final String PATH_STRATEGY_EXCLUDE = "/exclude"; - private static final String PATH_STRATEGY_INCLUDE = "/include"; + protected static final String PATH_STRATEGY_EXCLUDE = "/exclude"; + protected static final String PATH_STRATEGY_INCLUDE = "/include"; protected final String ruleKey; protected final String messageKey; - protected String parameterName; + protected final String defaultParameterName; protected final boolean applyToParameterizedPaths; - protected Set paths; + protected List paths; protected JsonNode rootNode; - @RuleProperty( - key = "paths", - description = "List of explicit paths to include/exclude from this rule separated by comma", - defaultValue = DEFAULT_PATH - ) - protected String pathsStr = DEFAULT_PATH; - - @RuleProperty( - key = "pathValidationStrategy", - description = "Path validation strategy (include/exclude)", - defaultValue = PATH_STRATEGY - ) - protected String pathCheckStrategy = PATH_STRATEGY; - protected AbstractQueryParameterCheck( String ruleKey, String messageKey, - String parameterName, + String defaultParameterName, boolean applyToParameterizedPaths ) { this.ruleKey = ruleKey; this.messageKey = messageKey; - this.parameterName = parameterName; + this.defaultParameterName = defaultParameterName; this.applyToParameterizedPaths = applyToParameterizedPaths; } + protected abstract String getPathsStr(); + + protected abstract String getPathCheckStrategy(); + + protected String getParameterName() { + return defaultParameterName; + } + @Override public Set subscribedKinds() { return ImmutableSet.of(OpenApi2Grammar.OPERATION, OpenApi3Grammar.OPERATION, OpenApi31Grammar.OPERATION, OpenApi32Grammar.OPERATION); @@ -65,7 +60,7 @@ public Set subscribedKinds() { @Override protected void visitFile(JsonNode root) { this.rootNode = root; - paths = parsePaths(pathsStr); + paths = parsePaths(getPathsStr()); super.visitFile(root); } @@ -86,7 +81,7 @@ public void visitNode(JsonNode node) { if (shouldIncludePath(path) && !hasParameter) { addIssue( ruleKey, - translate(messageKey, parameterName), + translate(messageKey, getParameterName()), node.key() ); } @@ -118,7 +113,7 @@ protected boolean hasNamedRefParameter(JsonNode parameterNode) { if (refParameterNode != null) { JsonNode nameNode = refParameterNode.get("name"); JsonNode inNode = refParameterNode.get("in"); - return inNode != null && "query".equals(inNode.getTokenValue()) && nameNode != null && parameterName.equals(nameNode.getTokenValue()); + return inNode != null && "query".equals(inNode.getTokenValue()) && nameNode != null && getParameterName().equals(nameNode.getTokenValue()); } return false; } @@ -126,7 +121,7 @@ protected boolean hasNamedRefParameter(JsonNode parameterNode) { protected boolean hasDirectParameter(JsonNode parameterNode) { JsonNode nameNode = parameterNode.get("name"); JsonNode inNode = parameterNode.get("in"); - return inNode != null && "query".equals(inNode.getTokenValue()) && nameNode != null && parameterName.equals(nameNode.getTokenValue()); + return inNode != null && "query".equals(inNode.getTokenValue()) && nameNode != null && getParameterName().equals(nameNode.getTokenValue()); } protected String getPath(JsonNode node) { @@ -143,12 +138,13 @@ protected String getPath(JsonNode node) { protected boolean shouldIncludePath(String path) { if (paths.isEmpty()) { - return pathCheckStrategy.equals(PATH_STRATEGY_EXCLUDE); + return getPathCheckStrategy().equals(PATH_STRATEGY_EXCLUDE); } - if (pathCheckStrategy.equals(PATH_STRATEGY_EXCLUDE)) { - return !paths.contains(path); - } else if (pathCheckStrategy.equals(PATH_STRATEGY_INCLUDE)) { - return paths.contains(path); + boolean matchesList = paths.stream().anyMatch(p -> p.matcher(path).find()); + if (getPathCheckStrategy().equals(PATH_STRATEGY_EXCLUDE)) { + return !matchesList; + } else if (getPathCheckStrategy().equals(PATH_STRATEGY_INCLUDE)) { + return matchesList; } return false; } @@ -161,13 +157,15 @@ protected boolean endsWithPathParam(String path) { return last.matches("^\\{[^}]+\\}$"); } - protected Set parsePaths(String pathsStr) { - if (!pathsStr.trim().isEmpty()) { + protected List parsePaths(String pathsStr) { + if (pathsStr != null && !pathsStr.trim().isEmpty()) { return Arrays.stream(pathsStr.split(",")) .map(String::trim) - .collect(Collectors.toSet()); + .filter(s -> !s.isEmpty()) + .map(segment -> Pattern.compile(Pattern.quote(segment) + "(/|$)")) + .collect(Collectors.toList()); } else { - return new HashSet<>(); + return new ArrayList<>(); } } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheck.java index 262bc099..04a735df 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheck.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi.checks.parameters; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR019SelectParameterCheck.KEY) public class OAR019SelectParameterCheck extends AbstractQueryParameterCheck { @@ -8,6 +9,29 @@ public class OAR019SelectParameterCheck extends AbstractQueryParameterCheck { public static final String KEY = "OAR019"; private static final String MESSAGE = "OAR019.error"; private static final String PARAM_NAME = "$select"; + private static final String DEFAULT_PATHS = "/me,/health,/ping,/status"; + private static final String PATH_STRATEGY = "/exclude"; + + @RuleProperty( + key = "parameterName", + description = "Name of the parameter to be checked", + defaultValue = PARAM_NAME + ) + private String parameterNameOverride = PARAM_NAME; + + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATHS + ) + private String pathsOverride = DEFAULT_PATHS; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategyOverride = PATH_STRATEGY; public OAR019SelectParameterCheck() { super( @@ -18,4 +42,19 @@ public OAR019SelectParameterCheck() { ); } + @Override + protected String getParameterName() { + return parameterNameOverride; + } + + @Override + protected String getPathsStr() { + return pathsOverride; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategyOverride; + } + } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheck.java index fdac58e8..a2b0c1c6 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheck.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi.checks.parameters; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR020ExpandParameterCheck.KEY) public class OAR020ExpandParameterCheck extends AbstractCollectionQueryParameterCheck { @@ -8,8 +9,46 @@ public class OAR020ExpandParameterCheck extends AbstractCollectionQueryParameter public static final String KEY = "OAR020"; private static final String MESSAGE = "OAR020.error"; private static final String PARAM_NAME = "$expand"; + private static final String DEFAULT_PATHS = "/me,/health,/ping,/status"; + private static final String PATH_STRATEGY = "/exclude"; + + @RuleProperty( + key = "parameterName", + description = "Name of the parameter to be checked", + defaultValue = PARAM_NAME + ) + private String parameterNameOverride = PARAM_NAME; + + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATHS + ) + private String pathsOverride = DEFAULT_PATHS; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategyOverride = PATH_STRATEGY; public OAR020ExpandParameterCheck() { super(KEY, MESSAGE, PARAM_NAME, false); } + + @Override + protected String getParameterName() { + return parameterNameOverride; + } + + @Override + protected String getPathsStr() { + return pathsOverride; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategyOverride; + } } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheck.java index a8b52bfc..346a3607 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheck.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi.checks.parameters; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR021ExcludeParameterCheck.KEY) public class OAR021ExcludeParameterCheck extends AbstractCollectionQueryParameterCheck { @@ -8,8 +9,46 @@ public class OAR021ExcludeParameterCheck extends AbstractCollectionQueryParamete public static final String KEY = "OAR021"; private static final String MESSAGE = "OAR021.error"; private static final String PARAM_NAME = "$exclude"; + private static final String DEFAULT_PATHS = "/me,/health,/ping,/status"; + private static final String PATH_STRATEGY = "/exclude"; + + @RuleProperty( + key = "parameterName", + description = "Name of the parameter to be checked", + defaultValue = PARAM_NAME + ) + private String parameterNameOverride = PARAM_NAME; + + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATHS + ) + private String pathsOverride = DEFAULT_PATHS; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategyOverride = PATH_STRATEGY; public OAR021ExcludeParameterCheck() { super(KEY, MESSAGE, PARAM_NAME, false); } + + @Override + protected String getParameterName() { + return parameterNameOverride; + } + + @Override + protected String getPathsStr() { + return pathsOverride; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategyOverride; + } } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheck.java index 0cbe783e..ea2c70fc 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheck.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi.checks.parameters; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR022OrderbyParameterCheck.KEY) public class OAR022OrderbyParameterCheck extends AbstractQueryParameterCheck { @@ -9,6 +10,20 @@ public class OAR022OrderbyParameterCheck extends AbstractQueryParameterCheck { private static final String MESSAGE = "OAR022.error"; private static final String PARAM_NAME = "$orderby"; + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATH + ) + private String pathsStr = DEFAULT_PATH; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategy = PATH_STRATEGY; + public OAR022OrderbyParameterCheck() { super( KEY, @@ -17,4 +32,14 @@ public OAR022OrderbyParameterCheck() { false ); } + + @Override + protected String getPathsStr() { + return pathsStr; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategy; + } } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR023TotalParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR023TotalParameterCheck.java index 8337d644..9cffb226 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR023TotalParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR023TotalParameterCheck.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi.checks.parameters; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR023TotalParameterCheck.KEY) public class OAR023TotalParameterCheck extends AbstractQueryParameterCheck { @@ -9,6 +10,20 @@ public class OAR023TotalParameterCheck extends AbstractQueryParameterCheck { private static final String MESSAGE = "OAR023.error"; private static final String PARAM_NAME = "$total"; + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATH + ) + private String pathsStr = DEFAULT_PATH; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategy = PATH_STRATEGY; + public OAR023TotalParameterCheck() { super( KEY, @@ -17,4 +32,14 @@ public OAR023TotalParameterCheck() { true ); } + + @Override + protected String getPathsStr() { + return pathsStr; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategy; + } } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR024StartParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR024StartParameterCheck.java index aedcaafa..6da4d16b 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR024StartParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR024StartParameterCheck.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi.checks.parameters; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR024StartParameterCheck.KEY) public class OAR024StartParameterCheck extends AbstractQueryParameterCheck { @@ -9,6 +10,20 @@ public class OAR024StartParameterCheck extends AbstractQueryParameterCheck { private static final String MESSAGE = "OAR024.error"; private static final String PARAM_NAME = "$start"; + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATH + ) + private String pathsStr = DEFAULT_PATH; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategy = PATH_STRATEGY; + public OAR024StartParameterCheck() { super( KEY, @@ -17,4 +32,14 @@ public OAR024StartParameterCheck() { true ); } + + @Override + protected String getPathsStr() { + return pathsStr; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategy; + } } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheck.java index 2ea5e207..8268f050 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheck.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi.checks.parameters; import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; @Rule(key = OAR025LimitParameterCheck.KEY) public class OAR025LimitParameterCheck extends AbstractQueryParameterCheck { @@ -9,6 +10,20 @@ public class OAR025LimitParameterCheck extends AbstractQueryParameterCheck { private static final String MESSAGE = "OAR025.error"; private static final String PARAM_NAME = "$limit"; + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATH + ) + private String pathsStr = DEFAULT_PATH; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategy = PATH_STRATEGY; + public OAR025LimitParameterCheck() { super( KEY, @@ -17,4 +32,14 @@ public OAR025LimitParameterCheck() { false ); } + + @Override + protected String getPathsStr() { + return pathsStr; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategy; + } } \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR028FilterParameterCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR028FilterParameterCheck.java index 703e56e9..f39117d0 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR028FilterParameterCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/parameters/OAR028FilterParameterCheck.java @@ -1,6 +1,5 @@ package apiaddicts.sonar.openapi.checks.parameters; -import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode; import org.sonar.check.Rule; import org.sonar.check.RuleProperty; @@ -18,13 +17,36 @@ public class OAR028FilterParameterCheck extends AbstractCollectionQueryParameter ) private String filterParamName = DEFAULT_PARAM_NAME; + @RuleProperty( + key = "paths", + description = "List of explicit paths to include/exclude from this rule separated by comma", + defaultValue = DEFAULT_PATH + ) + private String pathsStr = DEFAULT_PATH; + + @RuleProperty( + key = "pathValidationStrategy", + description = "Path validation strategy (include/exclude)", + defaultValue = PATH_STRATEGY + ) + private String pathCheckStrategy = PATH_STRATEGY; + public OAR028FilterParameterCheck() { super(KEY, MESSAGE, DEFAULT_PARAM_NAME, false); } @Override - protected void visitFile(JsonNode root) { - this.parameterName = filterParamName; - super.visitFile(root); + protected String getParameterName() { + return filterParamName; + } + + @Override + protected String getPathsStr() { + return pathsStr; + } + + @Override + protected String getPathCheckStrategy() { + return pathCheckStrategy; } } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR076NumericFormatCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR076NumericFormatCheck.java index 0a6286e5..47cc722d 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR076NumericFormatCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR076NumericFormatCheck.java @@ -13,7 +13,7 @@ public class OAR076NumericFormatCheck extends AbstractFormatCheck { private static final String MESSAGE = "OAR076.error"; @Override - public void validate(String type, String format, JsonNode typeNode) { + public void validate(String type, String format, JsonNode typeNode, JsonNode node) { boolean isInvalid = false; if ("integer".equals(type)) { diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR082BinaryOrByteFormatCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR082BinaryOrByteFormatCheck.java index 0c831f4a..cbaf2ad1 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR082BinaryOrByteFormatCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR082BinaryOrByteFormatCheck.java @@ -31,13 +31,18 @@ public class OAR082BinaryOrByteFormatCheck extends BaseCheck { ) private String fieldsApply = FIELDS_TO_APPLY; - private List fieldsList = Arrays.asList(fieldsApply.split(",")); + private List fieldsList; @Override public Set subscribedKinds() { return ImmutableSet.of(OpenApi2Grammar.SCHEMA, OpenApi2Grammar.PARAMETER, OpenApi3Grammar.SCHEMA, OpenApi31Grammar.SCHEMA, OpenApi32Grammar.SCHEMA); } + @Override + protected void visitFile(JsonNode root) { + fieldsList = Arrays.asList(fieldsApply.split(",")); + } + @Override public void visitNode(JsonNode node) { visitV2Node(node); diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR085OpenAPIVersionCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR085OpenAPIVersionCheck.java index 2cc3ba66..7422bc70 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR085OpenAPIVersionCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/security/OAR085OpenAPIVersionCheck.java @@ -29,15 +29,14 @@ public class OAR085OpenAPIVersionCheck extends BaseCheck { ) private String validVersionsStr = DEFAULT_VALID_VERSIONS; - private final List validVersions = Arrays.asList(validVersionsStr.split(",")); - @Override protected void visitFile(JsonNode root) { JsonNode swaggerNode = root.get("swagger"); JsonNode openapiNode = root.get("openapi"); String version = getVersion(swaggerNode, openapiNode); - + List validVersions = Arrays.asList(validVersionsStr.split(",")); + if (version == null || !validVersions.contains(version)) { addIssue(KEY, translate(MESSAGE, version), root.key()); } diff --git a/src/main/resources/messages/errors.properties b/src/main/resources/messages/errors.properties index 3b47830f..78ab417f 100644 --- a/src/main/resources/messages/errors.properties +++ b/src/main/resources/messages/errors.properties @@ -37,7 +37,7 @@ OAR032.error=Ambiguous path parts not encouraged: {0} OAR033.error-header-required=''{0}'' header must be required OAR035.error=Response code {0} must be defined for operations with security schemes defined OAR036.error=Cookie use is forbidden as a session mechanism -OAR037.error=String types requires a valid format +OAR037.error=String types require a valid format, or a valid pattern when no format is defined OAR038.error=''data'' or ''error'' property is required OAR038.error-required-schema=Response schema is required OAR038.error-required-one-property=At least you have to define the identifier property diff --git a/src/main/resources/messages/errors_es.properties b/src/main/resources/messages/errors_es.properties index 738ba524..7b509b68 100644 --- a/src/main/resources/messages/errors_es.properties +++ b/src/main/resources/messages/errors_es.properties @@ -37,7 +37,7 @@ OAR032.error=Nombres de partes de path ambiguos no permitidos: {0} OAR033.error-header-required=La cabecera ''{0}'' debe ser obligatoria OAR035.error=El código de respuesta {0} debe estar definido cuando la operación tiene esquemas de seguridad definidos OAR036.error=El uso de cookies está prohibido como mecanismo de sesión -OAR037.error=Las propiedades de tipo string deben definir un formato válido +OAR037.error=Las propiedades de tipo string deben definir un formato válido o, si no hay formato, un pattern válido OAR038.error=La propiedad ''data'' o ''error'' es obligatoria OAR038.error-required-schema=El esquema de respuesta es obligatorio OAR038.error-required-one-property=Se debe de definir al menos una propiedad diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/core/OAR044.html b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/core/OAR044.html index 77bc10e6..221ea1bd 100644 --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/core/OAR044.html +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/core/OAR044.html @@ -65,31 +65,35 @@

Solución compatible (OpenAPI 2)

JSON

 {
-    "swagger": "2.0", 
+    "swagger": "2.0",
     "info": {
-        "version": "1.0.0", 
+        "version": "1.0.0",
         "title": "Swagger Petstore"
-    }, 
+    },
     "produces": [
-        "application/json", 
-        "text/plain"
-    ], 
+        "application/json",
+        "text/plain",
+        "application/vnd.ms-excel",
+        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        "application/ld+json"
+    ],
     "consumes": [
-        "application/json", 
-        "text/plain"
-    ], 
+        "application/json",
+        "text/plain",
+        "application/vnd.ms-excel"
+    ],
     "paths": {
         "/pets": {
             "get": {
                 "produces": [
-                    "application/json", 
+                    "application/json",
                     "text/plain"
-                ], 
+                ],
                 "consumes": [
-                    "application/json", 
+                    "application/json",
                     "text/plain"
-                ], 
-                "responses": { 
+                ],
+                "responses": {
                     "200": {
                         "description": "some operation"
                     }
@@ -108,9 +112,13 @@ 

YAML

produces: - application/json - text/plain + - application/vnd.ms-excel + - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + - application/ld+json consumes: - application/json - text/plain + - application/vnd.ms-excel paths: /pets: get: @@ -128,24 +136,28 @@

Ejemplo de código no compatible (OpenAPI 3)

JSON

 {
-    "openapi": "3.0.1", 
+    "openapi": "3.0.1",
     "info": {
-        "version": "1.0.0", 
+        "version": "1.0.0",
         "title": "Swagger Petstore"
-    }, 
+    },
     "paths": {
-        "/pets": null, 
-        "post": {
-            "requestBody": null, 
-            "content": {
-                "application": {}, 
-                "text/*": {}
-            }, 
-            "responses": null, 
-            "200": {
-                "description": "some operation", 
-                "content": null, 
-                "application": {}
+        "/pets": {
+            "post": {
+                "requestBody": {
+                    "content": {
+                        "application": {},
+                        "invalid-no-slash": {}
+                    }
+                },
+                "responses": {
+                    "200": {
+                        "description": "some operation",
+                        "content": {
+                            "application": {}
+                        }
+                    }
+                }
             }
         }
     }
@@ -163,7 +175,7 @@ 

YAML

requestBody: content: 'application': {} - 'text/*': {} + 'invalid-no-slash': {} responses: '200': description: some operation @@ -174,25 +186,35 @@

Solución compatible (OpenAPI 3)

JSON

 {
-    "openapi": "3.0.1", 
+    "openapi": "3.0.1",
     "info": {
-        "version": "1.0.0", 
+        "version": "1.0.0",
         "title": "Swagger Petstore"
-    }, 
+    },
     "paths": {
         "/pets": {
             "post": {
-                "requestBody": { 
+                "requestBody": {
                     "content": {
-                        "application/json": {}, 
-                        "text/plain": {}
+                        "application/json": {},
+                        "multipart/form-data": {},
+                        "application/vnd.ms-excel": {},
+                        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {},
+                        "application/ld+json": {},
+                        "image/*": {},
+                        "*/*": {}
                     }
                 },
                 "responses": {
                     "200": {
-                        "description": "some operation", 
+                        "description": "some operation",
                         "content": {
-                            "application/json": {}
+                            "application/json": {},
+                            "text/csv": {},
+                            "image/png": {},
+                            "text/plain; charset=utf-8": {},
+                            "application/vnd.ms-excel": {},
+                            "application/vnd.github+json": {}
                         }
                     }
                 }
@@ -213,10 +235,20 @@ 

YAML

requestBody: content: 'application/json': {} - 'text/plain': {} + 'multipart/form-data': {} + 'application/vnd.ms-excel': {} + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {} + 'application/ld+json': {} + 'image/*': {} + '*/*': {} responses: '200': description: some operation content: 'application/json': {} + 'text/csv': {} + 'image/png': {} + 'text/plain; charset=utf-8': {} + 'application/vnd.ms-excel': {} + 'application/vnd.github+json': {}
\ No newline at end of file diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.html b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.html index 7f3e14a0..ce3e0344 100644 --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.html +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.html @@ -1,5 +1,10 @@ -

Una propiedad de tipo string sin formato, o con un formato no reconocido, puede provocar una implementación incorrecta de la API.

-

Esta regla dispara cuando el campo format está ausente o presente pero no es reconocido. Todo schema de tipo string debe declarar uno de los formatos válidos.

+

Una propiedad de tipo string sin un format reconocido y sin un pattern válido puede permitir la entrada de valores arbitrarios sin validar, lo que puede llevar a implementaciones inseguras o incorrectas de la API.

+

Esta regla exige que todo schema de tipo string restrinja sus valores de una de estas dos formas:

+
    +
  • declarando un campo format con un valor reconocido, o
  • +
  • si no se declara format, declarando un campo pattern que sea una expresión regular no vacía y sintácticamente válida.
  • +
+

La regla dispara cuando format está presente pero no es reconocido, o cuando format está ausente y pattern está ausente, vacío, o no es una expresión regular sintácticamente válida.

Formatos válidos: date, date-time, password, byte, binary, email, uuid, uri, hostname, ipv4, ipv6, HEX, HEX(16), json, xml, base64.

Configurable: formats-allowed — lista de formatos permitidos separados por coma (por defecto: la lista anterior).

Ejemplo de código no compatible (OpenAPI 2)

@@ -19,10 +24,10 @@

Ejemplo de código no compatible (OpenAPI 2)

items: type: object properties: - name: - type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato válido}} — format ausente + id: + type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato o pattern válido}} — sin format, sin pattern date: - type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato válido}} — format inválido + type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato o pattern válido}} — format inválido format: 'dd/mm/yyyy'

Solución compatible (OpenAPI 2)

@@ -42,6 +47,9 @@

Solución compatible (OpenAPI 2)

items: type: object properties: + id: + type: string + pattern: '^[A-Z]{3}-\d+$' date: type: string format: date @@ -65,10 +73,10 @@

Ejemplo de código no compatible (OpenAPI 3)

items: type: object properties: - name: - type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato válido}} — format ausente + id: + type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato o pattern válido}} — sin format, sin pattern date: - type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato válido}} — format inválido + type: string # No conforme {{OAR037: Las propiedades de tipo string deben definir un formato o pattern válido}} — format inválido format: dd/mm/yyyy

Solución compatible (OpenAPI 3)

@@ -90,7 +98,10 @@

Solución compatible (OpenAPI 3)

items: type: object properties: + id: + type: string + pattern: '^[A-Z]{3}-\d+$' date: type: string format: date - \ No newline at end of file + diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.json b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.json index 07772b02..7e563a3a 100644 --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.json +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR037.json @@ -1,13 +1,13 @@ { - "title": "OAR037 - StringFormat - Los tipos string requieren un formato válido", - "type": "BUG", + "title": "OAR037 - StringFormat - Los tipos string requieren un formato o pattern válido", + "type": "VULNERABILITY", "status": "ready", "remediation": { "func": "Constant\/Issue", "constantCost": "30min" }, "tags": [ - "format" + "safety" ], "defaultSeverity": "MAJOR" } \ No newline at end of file diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR044.html b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR044.html index 60c71fb4..7965b70b 100644 --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR044.html +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/format/OAR044.html @@ -34,9 +34,13 @@

Solución compatible (OpenAPI 2)

produces: - application/json - text/plain + - application/vnd.ms-excel + - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + - application/ld+json consumes: - application/json - text/plain + - application/vnd.ms-excel paths: /pets: get: @@ -62,7 +66,7 @@

Ejemplo de código no compatible (OpenAPI 3)

requestBody: content: 'application': {} - 'text/*': {} + 'invalid-no-slash': {} responses: '200': description: some operation @@ -81,10 +85,20 @@

Solución compatible (OpenAPI 3)

requestBody: content: 'application/json': {} - 'text/plain': {} + 'multipart/form-data': {} + 'application/vnd.ms-excel': {} + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {} + 'application/ld+json': {} + 'image/*': {} + '*/*': {} responses: '200': description: some operation content: 'application/json': {} + 'text/csv': {} + 'image/png': {} + 'text/plain; charset=utf-8': {} + 'application/vnd.ms-excel': {} + 'application/vnd.github+json': {} \ No newline at end of file diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/operations/OAR017.html b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/operations/OAR017.html index 668d7d4e..aef0567a 100644 --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/operations/OAR017.html +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/operations/OAR017.html @@ -4,7 +4,7 @@
  • Aparecen dos segmentos consecutivos del mismo tipo: dos segmentos estáticos (p.ej. /a/b) o dos parámetros de ruta (p.ej. /{a}/{b}).
  • El path empieza por un parámetro de ruta (p.ej. /{id}/items).
  • -

    Configurable: exclude_patterns (por defecto: get,me,search) — segmentos tratados como pseudo-parámetros que no rompen la regla de alternación.

    +

    Configurable: exclude_patterns (por defecto: get,me,search,delete) — segmentos tratados como pseudo-parámetros que no rompen la regla de alternación.

    Ejemplo de código no compatible (OpenAPI 2)

     swagger: "2.0"
    diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR022.html b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR022.html
    index 93c17629..f0b86367 100644
    --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR022.html
    +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR022.html
    @@ -1,4 +1,5 @@
     

    El parámetro elegido debe definirse en esta operación. Por defecto, $orderby

    +

    Esta regla se aplica únicamente a endpoints GET de colección. Los paths que terminan con un parámetro de ruta (p. ej. /examples/{id}) se consideran endpoints de recurso único y quedan excluidos automáticamente.

    Ejemplo de código no compatible (OpenAPI 2)

       swagger: "2.0"
    diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR025.html b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR025.html
    index 235d4f29..84e5d1bc 100644
    --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR025.html
    +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/parameters/OAR025.html
    @@ -1,4 +1,5 @@
     

    El parámetro elegido debe definirse en esta operación. Por defecto, $limit

    +

    Esta regla se aplica únicamente a endpoints GET de colección. Los paths que terminan con un parámetro de ruta (p. ej. /examples/{id}) se consideran endpoints de recurso único y quedan excluidos automáticamente.

    Ejemplo de código no compatible (OpenAPI 2)

       swagger: "2.0"
    diff --git a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/resources/OAR017.html b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/resources/OAR017.html
    index b8177471..b3884acb 100644
    --- a/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/resources/OAR017.html
    +++ b/src/main/resources/org/sonar/l10n/es/openapi/rules/openapi/resources/OAR017.html
    @@ -4,7 +4,7 @@
       
  • Aparecen dos segmentos consecutivos del mismo tipo: dos segmentos estáticos (p.ej. /a/b) o dos parámetros de ruta (p.ej. /{a}/{b}).
  • El path empieza por un parámetro de ruta (p.ej. /{id}/items).
  • -

    Configurable: exclude_patterns (por defecto: get,me,search) — segmentos tratados como pseudo-parámetros que no rompen la regla de alternación.

    +

    Configurable: exclude_patterns (por defecto: get,me,search,delete) — segmentos tratados como pseudo-parámetros que no rompen la regla de alternación.

    Ejemplo de código no compatible (OpenAPI 2)

    JSON

    diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/core/OAR044.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/core/OAR044.html
    index 07ab977f..202b2e9a 100644
    --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/core/OAR044.html
    +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/core/OAR044.html
    @@ -65,30 +65,34 @@ 

    Compliant Solution (OpenAPI 2)

    JSON

     {
    -    "swagger": "2.0", 
    +    "swagger": "2.0",
         "info": {
    -        "version": "1.0.0", 
    +        "version": "1.0.0",
             "title": "Swagger Petstore"
    -    }, 
    +    },
         "produces": [
    -        "application/json", 
    -        "text/plain"
    -    ], 
    +        "application/json",
    +        "text/plain",
    +        "application/vnd.ms-excel",
    +        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    +        "application/ld+json"
    +    ],
         "consumes": [
    -        "application/json", 
    -        "text/plain"
    -    ], 
    +        "application/json",
    +        "text/plain",
    +        "application/vnd.ms-excel"
    +    ],
         "paths": {
             "/pets": {
                 "get": {
                     "produces": [
    -                    "application/json", 
    +                    "application/json",
                         "text/plain"
    -                ], 
    +                ],
                     "consumes": [
    -                    "application/json", 
    +                    "application/json",
                         "text/plain"
    -                ], 
    +                ],
                     "responses": {
                         "200": {
                             "description": "some operation"
    @@ -108,9 +112,13 @@ 

    YAML

    produces: - application/json - text/plain + - application/vnd.ms-excel + - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + - application/ld+json consumes: - application/json - text/plain + - application/vnd.ms-excel paths: /pets: get: @@ -128,24 +136,28 @@

    Noncompliant Code Example (OpenAPI 3)

    JSON

     {
    -    "openapi": "3.0.1", 
    +    "openapi": "3.0.1",
         "info": {
    -        "version": "1.0.0", 
    +        "version": "1.0.0",
             "title": "Swagger Petstore"
    -    }, 
    +    },
         "paths": {
    -        "/pets": null, 
    -        "post": {
    -            "requestBody": null, 
    -            "content": {
    -                "application": {}, 
    -                "text/*": {}
    -            }, 
    -            "responses": null, 
    -            "200": {
    -                "description": "some operation", 
    -                "content": null, 
    -                "application": {}
    +        "/pets": {
    +            "post": {
    +                "requestBody": {
    +                    "content": {
    +                        "application": {},
    +                        "invalid-no-slash": {}
    +                    }
    +                },
    +                "responses": {
    +                    "200": {
    +                        "description": "some operation",
    +                        "content": {
    +                            "application": {}
    +                        }
    +                    }
    +                }
                 }
             }
         }
    @@ -163,7 +175,7 @@ 

    YAML

    requestBody: content: 'application': {} - 'text/*': {} + 'invalid-no-slash': {} responses: '200': description: some operation @@ -174,25 +186,35 @@

    Compliant Solution (OpenAPI 3)

    JSON

     {
    -    "openapi": "3.0.1", 
    +    "openapi": "3.0.1",
         "info": {
    -        "version": "1.0.0", 
    +        "version": "1.0.0",
             "title": "Swagger Petstore"
    -    }, 
    +    },
         "paths": {
             "/pets": {
                 "post": {
                     "requestBody": {
                         "content": {
    -                        "application/json": {}, 
    -                        "text/plain": {}
    +                        "application/json": {},
    +                        "multipart/form-data": {},
    +                        "application/vnd.ms-excel": {},
    +                        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {},
    +                        "application/ld+json": {},
    +                        "image/*": {},
    +                        "*/*": {}
                         }
    -                }, 
    -                "responses": { 
    +                },
    +                "responses": {
                         "200": {
    -                        "description": "some operation", 
    +                        "description": "some operation",
                             "content": {
    -                            "application/json": {}
    +                            "application/json": {},
    +                            "text/csv": {},
    +                            "image/png": {},
    +                            "text/plain; charset=utf-8": {},
    +                            "application/vnd.ms-excel": {},
    +                            "application/vnd.github+json": {}
                             }
                         }
                     }
    @@ -213,10 +235,20 @@ 

    YAML

    requestBody: content: 'application/json': {} - 'text/plain': {} + 'multipart/form-data': {} + 'application/vnd.ms-excel': {} + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {} + 'application/ld+json': {} + 'image/*': {} + '*/*': {} responses: '200': description: some operation content: 'application/json': {} + 'text/csv': {} + 'image/png': {} + 'text/plain; charset=utf-8': {} + 'application/vnd.ms-excel': {} + 'application/vnd.github+json': {}
    \ No newline at end of file diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/examples/OAR031.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/examples/OAR031.html index 78956b46..c20f54bc 100644 --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/examples/OAR031.html +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/examples/OAR031.html @@ -1,4 +1,6 @@

    The examples can help developers to understand the response data structure and representation.

    +

    Examples are validated as four independent levels: response, request body, parameter and property. The response, request-body and parameter levels require an example declared at the media-type or schema root; examples nested inside individual properties do not satisfy them. 204 responses are excluded.

    +

    Each level can be enabled or disabled independently with the rule parameters validate-response, validate-request-body, validate-parameter and validate-property (all enabled by default).

    Noncompliant Code Example (OpenAPI 2)

     swagger: "2.0"
    diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.html
    index 2ec09784..64fe2c3c 100644
    --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.html
    +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.html
    @@ -1,5 +1,10 @@
    -

    A string schema without a format, or with an unrecognized format, may cause developers to use the wrong variable types in the API implementation.

    -

    This rule fires when the format field is absent or present but not recognized. Every string schema must declare one of the valid formats.

    +

    A string schema without a recognized format and without a valid pattern may allow arbitrary, unvalidated input, which can lead developers to use the wrong variable types or to accept unsafe values in the API implementation.

    +

    This rule requires every string schema to constrain its values in one of two ways:

    +
      +
    • declare a format field with a recognized value, or
    • +
    • if no format is declared, declare a pattern field that is a non-empty, syntactically valid regular expression.
    • +
    +

    The rule fires when format is present but not recognized, or when format is absent and pattern is missing, empty, or not a syntactically valid regular expression.

    Valid formats: date, date-time, password, byte, binary, email, uuid, uri, hostname, ipv4, ipv6, HEX, HEX(16), json, xml, base64.

    Configurable: formats-allowed — comma-separated list of allowed formats (default: the list above).

    Noncompliant Code Example (OpenAPI 2)

    @@ -19,10 +24,10 @@

    Noncompliant Code Example (OpenAPI 2)

    items: type: object properties: - name: - type: string # Noncompliant {{OAR037: String types requires a valid format}} — no format + id: + type: string # Noncompliant {{OAR037: String types require a valid format or pattern}} — no format, no pattern date: - type: string # Noncompliant {{OAR037: String types requires a valid format}} — invalid format + type: string # Noncompliant {{OAR037: String types require a valid format or pattern}} — invalid format format: 'dd/mm/yyyy'

    Compliant Solution (OpenAPI 2)

    @@ -42,6 +47,9 @@

    Compliant Solution (OpenAPI 2)

    items: type: object properties: + id: + type: string + pattern: '^[A-Z]{3}-\d+$' date: type: string format: date @@ -65,10 +73,10 @@

    Noncompliant Code Example (OpenAPI 3)

    items: type: object properties: - name: - type: string # Noncompliant {{OAR037: String types requires a valid format}} — no format + id: + type: string # Noncompliant {{OAR037: String types require a valid format or pattern}} — no format, no pattern date: - type: string # Noncompliant {{OAR037: String types requires a valid format}} — invalid format + type: string # Noncompliant {{OAR037: String types require a valid format or pattern}} — invalid format format: dd/mm/yyyy

    Compliant Solution (OpenAPI 3)

    @@ -90,7 +98,10 @@

    Compliant Solution (OpenAPI 3)

    items: type: object properties: + id: + type: string + pattern: '^[A-Z]{3}-\d+$' date: type: string format: date -
    \ No newline at end of file +
    diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.json b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.json index c0032cf4..9e95db6b 100644 --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.json +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR037.json @@ -1,13 +1,13 @@ { - "title": "OAR037 - StringFormat - String types requires a valid format", - "type": "BUG", + "title": "OAR037 - StringFormat - String types require a valid format or pattern", + "type": "VULNERABILITY", "status": "ready", "remediation": { "func": "Constant\/Issue", "constantCost": "30min" }, "tags": [ - "format" + "safety" ], "defaultSeverity": "MAJOR" } \ No newline at end of file diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR044.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR044.html index 008ed872..4ecec85a 100644 --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR044.html +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/format/OAR044.html @@ -34,9 +34,13 @@

    Compliant Solution (OpenAPI 2)

    produces: - application/json - text/plain + - application/vnd.ms-excel + - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + - application/ld+json consumes: - application/json - text/plain + - application/vnd.ms-excel paths: /pets: get: @@ -62,7 +66,7 @@

    Noncompliant Code Example (OpenAPI 3)

    requestBody: content: 'application': {} # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} - 'text/*': {} + 'invalid-no-slash': {} # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} responses: '200': description: some operation @@ -81,10 +85,20 @@

    Compliant Solution (OpenAPI 3)

    requestBody: content: 'application/json': {} - 'text/plain': {} + 'multipart/form-data': {} + 'application/vnd.ms-excel': {} + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {} + 'application/ld+json': {} + 'image/*': {} + '*/*': {} responses: '200': description: some operation content: 'application/json': {} + 'text/csv': {} + 'image/png': {} + 'text/plain; charset=utf-8': {} + 'application/vnd.ms-excel': {} + 'application/vnd.github+json': {}
    \ No newline at end of file diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/operations/OAR017.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/operations/OAR017.html index 22bce347..f6fe52d2 100644 --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/operations/OAR017.html +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/operations/OAR017.html @@ -4,7 +4,7 @@
  • Two consecutive path segments of the same type appear: two static segments (e.g. /a/b) or two path parameters (e.g. /{a}/{b}).
  • The path starts with a path parameter (e.g. /{id}/items).
  • -

    Configurable: exclude_patterns (default: get,me,search) — segments treated as pseudo-parameters that do not break the alternation rule.

    +

    Configurable: exclude_patterns (default: get,me,search,delete) — segments treated as pseudo-parameters that do not break the alternation rule.

    Noncompliant Code Example (OpenAPI 2)

     swagger: "2.0"
    diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR022.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR022.html
    index 5917921e..2d816f82 100644
    --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR022.html
    +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR022.html
    @@ -1,4 +1,5 @@
     

    The chosen parameter must be defined in this operation. By default, $orderby

    +

    This rule applies only to collection GET endpoints. Paths ending with a path parameter (e.g. /examples/{id}) are treated as single-resource endpoints and are automatically excluded.

    Noncompliant Code Example (OpenAPI 2)

       swagger: "2.0"
    diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR025.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR025.html
    index d896113f..40d0873f 100644
    --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR025.html
    +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/parameters/OAR025.html
    @@ -1,4 +1,5 @@
     

    The chosen parameter must be defined in this operation. By default, $limit

    +

    This rule applies only to collection GET endpoints. Paths ending with a path parameter (e.g. /examples/{id}) are treated as single-resource endpoints and are automatically excluded.

    Noncompliant Code Example (OpenAPI 2)

       swagger: "2.0"
    diff --git a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/resources/OAR017.html b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/resources/OAR017.html
    index b33a7d6b..378a93fe 100644
    --- a/src/main/resources/org/sonar/l10n/openapi/rules/openapi/resources/OAR017.html
    +++ b/src/main/resources/org/sonar/l10n/openapi/rules/openapi/resources/OAR017.html
    @@ -4,7 +4,7 @@
     
  • Two consecutive path segments of the same type appear: two static segments (e.g. /a/b) or two path parameters (e.g. /{a}/{b}).
  • The path starts with a path parameter (e.g. /{id}/items).
  • -

    Configurable: exclude_patterns (default: get,me,search) — segments treated as pseudo-parameters that do not break the alternation rule.

    +

    Configurable: exclude_patterns (default: get,me,search,delete) — segments treated as pseudo-parameters that do not break the alternation rule.

    Noncompliant Code Example (OpenAPI 2)

    JSON

    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheckTest.java
    index 5cea16f8..4f7f624d 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheckTest.java
    @@ -4,6 +4,7 @@
     import org.junit.Test;
     import org.sonar.api.rule.Severity;
     import org.sonar.api.rules.RuleType;
    +import org.sonar.api.server.rule.RuleParamType;
     import apiaddicts.sonar.openapi.BaseCheckTest;
     
     public class OAR031ExamplesCheckTest extends BaseCheckTest {
    @@ -112,4 +113,13 @@ public void verifyRule() {
             assertRuleProperties("OAR031 - Examples - Responses, Request Body, Parameters and Properties must have an example defined", RuleType.BUG, Severity.MAJOR, tags("examples"));
         }
     
    +    @Override
    +    public void verifyParameters() {
    +        assertNumberOfParameters(4);
    +        assertParameterProperties("validateResponse", "true", RuleParamType.BOOLEAN);
    +        assertParameterProperties("validateRequestBody", "true", RuleParamType.BOOLEAN);
    +        assertParameterProperties("validateParameter", "true", RuleParamType.BOOLEAN);
    +        assertParameterProperties("validateProperty", "true", RuleParamType.BOOLEAN);
    +    }
    +
     }
    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheckTest.java
    index ad561e9b..fb04f56a 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/format/OAR037StringFormatCheckTest.java
    @@ -70,6 +70,11 @@ public void verifyInV2BlankFormat() {
             verifyV2("blank-format");
         }
     
    +    @Test
    +    public void verifyInV3PatternFallback() {
    +        verifyV3("no-format");
    +    }
    +
         @Override
         public void verifyParameters() {
             assertNumberOfParameters(1);
    @@ -78,6 +83,6 @@ public void verifyParameters() {
     
         @Override
         public void verifyRule() {
    -        assertRuleProperties("OAR037 - StringFormat - String types requires a valid format", RuleType.BUG, Severity.MAJOR, tags("format"));
    +        assertRuleProperties("OAR037 - StringFormat - String types require a valid format or pattern", RuleType.VULNERABILITY, Severity.MAJOR, tags("safety"));
         }
     }
    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheckTest.java
    index 88614748..54d9b77c 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/operations/OAR017ResourcePathCheckTest.java
    @@ -69,7 +69,7 @@ public void verifyRule() {
         @Override
         public void verifyParameters() {
             assertNumberOfParameters(1);
    -        assertParameterProperties("exclude_patterns", "get,me,search", RuleParamType.STRING);
    +        assertParameterProperties("exclude_patterns", "get,me,search,delete", RuleParamType.STRING);
         }
     
     }
    \ No newline at end of file
    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheckTest.java
    index 49359130..87631f99 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR019SelectParameterCheckTest.java
    @@ -117,8 +117,9 @@ public void verifyRule() {
     
         @Override
         public void verifyParameters() {
    -        assertNumberOfParameters(2);
    -        assertParameterProperties("paths", "/examples", RuleParamType.STRING);
    -        assertParameterProperties("pathValidationStrategy", "/include", RuleParamType.STRING);
    +        assertNumberOfParameters(3);
    +        assertParameterProperties("parameterName", "$select", RuleParamType.STRING);
    +        assertParameterProperties("paths", "/me,/health,/ping,/status", RuleParamType.STRING);
    +        assertParameterProperties("pathValidationStrategy", "/exclude", RuleParamType.STRING);
         }
     }
    \ No newline at end of file
    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheckTest.java
    index ceea3c8f..1be17b22 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR020ExpandParameterCheckTest.java
    @@ -41,7 +41,7 @@ public void verifyInV2WithRef() {
     
         @Test
         public void verifyInV2PathEndingWithParam() {
    -        verifyV3("with-param");
    +        verifyV2("with-param");
         }
     
         @Test
    @@ -150,8 +150,9 @@ public void verifyRule() {
     
         @Override
         public void verifyParameters() {
    -        assertNumberOfParameters(2);
    -        assertParameterProperties("paths", "/examples", RuleParamType.STRING);
    -        assertParameterProperties("pathValidationStrategy", "/include", RuleParamType.STRING);
    +        assertNumberOfParameters(3);
    +        assertParameterProperties("parameterName", "$expand", RuleParamType.STRING);
    +        assertParameterProperties("paths", "/me,/health,/ping,/status", RuleParamType.STRING);
    +        assertParameterProperties("pathValidationStrategy", "/exclude", RuleParamType.STRING);
         }
     }
    \ No newline at end of file
    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheckTest.java
    index 6cce39f9..da09cb4a 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR021ExcludeParameterCheckTest.java
    @@ -41,7 +41,7 @@ public void verifyInV2WithRef() {
     
         @Test
         public void verifyInV2PathEndingWithParam() {
    -        verifyV3("with-param");
    +        verifyV2("with-param");
         }
     
         @Test
    @@ -150,8 +150,9 @@ public void verifyRule() {
     
         @Override
         public void verifyParameters() {
    -        assertNumberOfParameters(2);
    -        assertParameterProperties("paths", "/examples", RuleParamType.STRING);
    -        assertParameterProperties("pathValidationStrategy", "/include", RuleParamType.STRING);
    +        assertNumberOfParameters(3);
    +        assertParameterProperties("parameterName", "$exclude", RuleParamType.STRING);
    +        assertParameterProperties("paths", "/me,/health,/ping,/status", RuleParamType.STRING);
    +        assertParameterProperties("pathValidationStrategy", "/exclude", RuleParamType.STRING);
         }
     }
    \ No newline at end of file
    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheckTest.java
    index e7fccdb3..89c741be 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR022OrderbyParameterCheckTest.java
    @@ -72,6 +72,23 @@ public void verifyInV32Without() {
             verifyV32("plain-without");
         }
     
    +    @Test
    +    public void verifyInV2SingleResource() {
    +        verifyV2("single-resource");
    +    }
    +    @Test
    +    public void verifyInV3SingleResource() {
    +        verifyV3("single-resource");
    +    }
    +    @Test
    +    public void verifyInV31SingleResource() {
    +        verifyV31("single-resource");
    +    }
    +    @Test
    +    public void verifyInV32SingleResource() {
    +        verifyV32("single-resource");
    +    }
    +
         @Override
         public void verifyRule() {
             assertRuleProperties("OAR022 - OrderbyParameter - the chosen parameter must be defined in this operation", RuleType.BUG, Severity.MINOR, tags("parameters"));
    diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheckTest.java
    index e6562b9d..463dfe8c 100644
    --- a/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheckTest.java
    +++ b/src/test/java/apiaddicts/sonar/openapi/checks/parameters/OAR025LimitParameterCheckTest.java
    @@ -72,6 +72,23 @@ public void verifyInV32Without() {
             verifyV32("plain-without");
         }
     
    +    @Test
    +    public void verifyInV2SingleResource() {
    +        verifyV2("single-resource");
    +    }
    +    @Test
    +    public void verifyInV3SingleResource() {
    +        verifyV3("single-resource");
    +    }
    +    @Test
    +    public void verifyInV31SingleResource() {
    +        verifyV31("single-resource");
    +    }
    +    @Test
    +    public void verifyInV32SingleResource() {
    +        verifyV32("single-resource");
    +    }
    +
         @Override
         public void verifyRule() {
             assertRuleProperties("OAR025 - LimitParameter - the chosen parameter must be defined in this operation", RuleType.BUG, Severity.MAJOR, tags("parameters"));
    diff --git a/src/test/resources/checks/v2/core/OAR044/media-type.json b/src/test/resources/checks/v2/core/OAR044/media-type.json
    index fb0e81ab..216fca4c 100644
    --- a/src/test/resources/checks/v2/core/OAR044/media-type.json
    +++ b/src/test/resources/checks/v2/core/OAR044/media-type.json
    @@ -18,6 +18,8 @@
             }
           },
           "post" : {
    +        "produces" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json", "text/csv", "image/png" ],
    +        "consumes" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json" ],
             "responses" : {
               "200" : {
                 "description" : "some operation"
    diff --git a/src/test/resources/checks/v2/core/OAR044/media-type.yaml b/src/test/resources/checks/v2/core/OAR044/media-type.yaml
    index 7a3a4849..fd2d08e0 100644
    --- a/src/test/resources/checks/v2/core/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v2/core/OAR044/media-type.yaml
    @@ -20,7 +20,17 @@ paths:
           responses:
             '200':
               description: some operation
    -    post: # without produces/consumes -> should not fail
    +    post:
    +      produces:
    +        - application/vnd.ms-excel
    +        - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    +        - application/ld+json
    +        - text/csv
    +        - image/png
    +      consumes:
    +        - application/vnd.ms-excel
    +        - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    +        - application/ld+json
           responses:
             '200':
               description: some operation
    \ No newline at end of file
    diff --git a/src/test/resources/checks/v2/examples/OAR031/externalref.yaml b/src/test/resources/checks/v2/examples/OAR031/externalref.yaml
    index 8b2b3bc2..18b488c1 100644
    --- a/src/test/resources/checks/v2/examples/OAR031/externalref.yaml
    +++ b/src/test/resources/checks/v2/examples/OAR031/externalref.yaml
    @@ -10,7 +10,7 @@ paths:
       /users:
         get:
           responses:
    -        200:
    +        200: # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: OK
               schema:
                 type: array
    @@ -27,7 +27,7 @@ paths:
               required: true
               type: string
           responses:
    -        200:
    +        200: # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: A single user
               schema:
                 $ref: '#/definitions/User'
    diff --git a/src/test/resources/checks/v2/examples/OAR031/nested-properties-examples.yaml b/src/test/resources/checks/v2/examples/OAR031/nested-properties-examples.yaml
    index 13ca46e6..6b0b4816 100644
    --- a/src/test/resources/checks/v2/examples/OAR031/nested-properties-examples.yaml
    +++ b/src/test/resources/checks/v2/examples/OAR031/nested-properties-examples.yaml
    @@ -6,7 +6,7 @@ paths:
       /profile:
         put:
           parameters:
    -        - name: body
    +        - name: body # Noncompliant {{OAR031: Parameters must have one or more examples defined}}
               in: body
               required: true
               schema:
    diff --git a/src/test/resources/checks/v2/examples/OAR031/valid.yaml b/src/test/resources/checks/v2/examples/OAR031/valid.yaml
    index abb84e89..299650c1 100644
    --- a/src/test/resources/checks/v2/examples/OAR031/valid.yaml
    +++ b/src/test/resources/checks/v2/examples/OAR031/valid.yaml
    @@ -12,6 +12,12 @@ paths:
               description: Pet list
               schema:
                 $ref: '#/definitions/pets'
    +          examples:
    +            application/json:
    +              size: 1
    +              pets:
    +                - name: Snow
    +                  type: dog
             default:
               $ref: "#/responses/server_error_response"
       /pets/{id}:
    @@ -23,6 +29,10 @@ paths:
               description: One pet
               schema:
                 $ref: "#/definitions/pet"
    +          examples:
    +            application/json:
    +              name: Snow
    +              type: dog
             default:
               $ref: "#/responses/server_error_response"
     
    @@ -63,4 +73,7 @@ responses:
           properties:
             error:
               type: string
    -          example: "Server error"
    \ No newline at end of file
    +          example: "Server error"
    +    examples:
    +      application/json:
    +        error: "Server error"
    \ No newline at end of file
    diff --git a/src/test/resources/checks/v2/format/OAR037/nested.json b/src/test/resources/checks/v2/format/OAR037/nested.json
    index 18663f0b..819ad8b7 100644
    --- a/src/test/resources/checks/v2/format/OAR037/nested.json
    +++ b/src/test/resources/checks/v2/format/OAR037/nested.json
    @@ -17,8 +17,12 @@
                       "type" : "object",
                       "properties" : {
                         "value" : {
    -                      "type" : "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                      "type" : "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                           "format" : "YYYY-MM-DD"
    +                    },
    +                    "code" : {
    +                      "type" : "string",
    +                      "pattern" : "^[A-Z]{3}-[0-9]+$"
                         }
                       }
                     }
    diff --git a/src/test/resources/checks/v2/format/OAR037/nested.yaml b/src/test/resources/checks/v2/format/OAR037/nested.yaml
    index 4ad7fd36..6a3c55c2 100644
    --- a/src/test/resources/checks/v2/format/OAR037/nested.yaml
    +++ b/src/test/resources/checks/v2/format/OAR037/nested.yaml
    @@ -15,6 +15,9 @@ paths:
                     type: object
                     properties:
                       value:
    -                    type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                         format: YYYY-MM-DD
    +                  code:
    +                    type: string
    +                    pattern: '^[A-Z]{3}-[0-9]+$'
     
    diff --git a/src/test/resources/checks/v2/format/OAR037/plain.json b/src/test/resources/checks/v2/format/OAR037/plain.json
    index 038c38a3..31df3943 100644
    --- a/src/test/resources/checks/v2/format/OAR037/plain.json
    +++ b/src/test/resources/checks/v2/format/OAR037/plain.json
    @@ -14,7 +14,15 @@
                   "type" : "object",
                   "properties" : {
                     "without" : {
    -                  "type" : "string" # Noncompliant {{OAR037: String types requires a valid format}}
    +                  "type" : "string" # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                },
    +                "withPattern" : {
    +                  "type" : "string",
    +                  "pattern" : "^[A-Z]{3}-[0-9]+$"
    +                },
    +                "withInvalidPattern" : {
    +                  "type" : "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                  "pattern" : "["
                     },
                     "date" : {
                       "type" : "string",
    @@ -61,7 +69,7 @@
                       "format" : "ipv6"
                     },
                     "other" : {
    -                  "type" : "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                  "type" : "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                       "format" : "YYYY-MM-DD"
                     }
                   }
    diff --git a/src/test/resources/checks/v2/format/OAR037/plain.yaml b/src/test/resources/checks/v2/format/OAR037/plain.yaml
    index 957f5bc1..a09e36e2 100644
    --- a/src/test/resources/checks/v2/format/OAR037/plain.yaml
    +++ b/src/test/resources/checks/v2/format/OAR037/plain.yaml
    @@ -12,7 +12,13 @@ paths:
                 type: object
                 properties:
                   without:
    -                type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +              withPattern:
    +                type: string
    +                pattern: '^[A-Z]{3}-[0-9]+$'
    +              withInvalidPattern:
    +                type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                pattern: '['
                   date:
                     type: string
                     format: date
    @@ -53,5 +59,5 @@ paths:
                     type: string
                     format: HEX(16)
                   other:
    -                type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                     format: YYYY-MM-DD
    diff --git a/src/test/resources/checks/v2/format/OAR037/with-$ref.json b/src/test/resources/checks/v2/format/OAR037/with-$ref.json
    index 5d9329d7..e9c50847 100644
    --- a/src/test/resources/checks/v2/format/OAR037/with-$ref.json
    +++ b/src/test/resources/checks/v2/format/OAR037/with-$ref.json
    @@ -32,8 +32,12 @@
           "type" : "object",
           "properties" : {
             "value" : {
    -          "type" : "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +          "type" : "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               "format" : "YYYY-MM-DD"
    +        },
    +        "code" : {
    +          "type" : "string",
    +          "pattern" : "^[A-Z]{3}-[0-9]+$"
             }
           }
         }
    diff --git a/src/test/resources/checks/v2/format/OAR037/with-$ref.yaml b/src/test/resources/checks/v2/format/OAR037/with-$ref.yaml
    index 3fea1aa9..a589efeb 100644
    --- a/src/test/resources/checks/v2/format/OAR037/with-$ref.yaml
    +++ b/src/test/resources/checks/v2/format/OAR037/with-$ref.yaml
    @@ -22,5 +22,8 @@ definitions:
         type: object
         properties:
           value:
    -        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
             format: YYYY-MM-DD
    +      code:
    +        type: string
    +        pattern: '^[A-Z]{3}-[0-9]+$'
    diff --git a/src/test/resources/checks/v2/format/OAR044/media-type.json b/src/test/resources/checks/v2/format/OAR044/media-type.json
    index fb0e81ab..216fca4c 100644
    --- a/src/test/resources/checks/v2/format/OAR044/media-type.json
    +++ b/src/test/resources/checks/v2/format/OAR044/media-type.json
    @@ -18,6 +18,8 @@
             }
           },
           "post" : {
    +        "produces" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json", "text/csv", "image/png" ],
    +        "consumes" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json" ],
             "responses" : {
               "200" : {
                 "description" : "some operation"
    diff --git a/src/test/resources/checks/v2/format/OAR044/media-type.yaml b/src/test/resources/checks/v2/format/OAR044/media-type.yaml
    index 7a3a4849..fd2d08e0 100644
    --- a/src/test/resources/checks/v2/format/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v2/format/OAR044/media-type.yaml
    @@ -20,7 +20,17 @@ paths:
           responses:
             '200':
               description: some operation
    -    post: # without produces/consumes -> should not fail
    +    post:
    +      produces:
    +        - application/vnd.ms-excel
    +        - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    +        - application/ld+json
    +        - text/csv
    +        - image/png
    +      consumes:
    +        - application/vnd.ms-excel
    +        - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    +        - application/ld+json
           responses:
             '200':
               description: some operation
    \ No newline at end of file
    diff --git a/src/test/resources/checks/v2/operations/OAR014/plain.json b/src/test/resources/checks/v2/operations/OAR014/plain.json
    index 7561c445..1dc0ee29 100644
    --- a/src/test/resources/checks/v2/operations/OAR014/plain.json
    +++ b/src/test/resources/checks/v2/operations/OAR014/plain.json
    @@ -95,7 +95,7 @@
             }
           }
         },
    -    "/one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six": { # Noncompliant {{OAR014: Resources depth level should be smaller}}
    +    "/one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six": {
           "get": {
             "responses": {
               "default": {
    @@ -104,7 +104,7 @@
             }
           }
         },
    -    "/one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six/{six}": { # Noncompliant {{OAR014: Resources depth level should be smaller}}
    +    "/one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six/{six}": {
           "get": {
             "responses": {
               "default": {
    diff --git a/src/test/resources/checks/v2/operations/OAR014/plain.yaml b/src/test/resources/checks/v2/operations/OAR014/plain.yaml
    index abae063e..5647b610 100644
    --- a/src/test/resources/checks/v2/operations/OAR014/plain.yaml
    +++ b/src/test/resources/checks/v2/operations/OAR014/plain.yaml
    @@ -53,12 +53,12 @@ paths:
           responses:
             default:
               description: Ok
    -  /one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six: # Noncompliant {{OAR014: Resources depth level should be smaller}}
    +  /one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six: # depth 6, out of the 4-5 non-suggested range (covered separately by OAR015)
         get:
           responses:
             default:
               description: Ok
    -  /one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six/{six}: # Noncompliant {{OAR014: Resources depth level should be smaller}}
    +  /one/{one}/two/{two}/three/{three}/four/{four}/five/{five}/six/{six}:
         get:
           responses:
             default:
    diff --git a/src/test/resources/checks/v2/operations/OAR017/plain.yaml b/src/test/resources/checks/v2/operations/OAR017/plain.yaml
    index 81d61480..249e07ea 100644
    --- a/src/test/resources/checks/v2/operations/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v2/operations/OAR017/plain.yaml
    @@ -43,6 +43,11 @@ paths:
           responses:
             200:
               description: "Ok"
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: "Ok"
       /one/{two}/{three}: # Noncompliant {{OAR017: Resource path should alternate static and parametrized parts}}
         get:
           responses:
    diff --git a/src/test/resources/checks/v2/parameters/OAR022/single-resource.json b/src/test/resources/checks/v2/parameters/OAR022/single-resource.json
    new file mode 100644
    index 00000000..3357f145
    --- /dev/null
    +++ b/src/test/resources/checks/v2/parameters/OAR022/single-resource.json
    @@ -0,0 +1,23 @@
    +{
    +  "swagger" : "2.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "type" : "string"
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v2/parameters/OAR022/single-resource.yaml b/src/test/resources/checks/v2/parameters/OAR022/single-resource.yaml
    new file mode 100644
    index 00000000..ae452772
    --- /dev/null
    +++ b/src/test/resources/checks/v2/parameters/OAR022/single-resource.yaml
    @@ -0,0 +1,14 @@
    +swagger: "2.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v2/parameters/OAR025/single-resource.json b/src/test/resources/checks/v2/parameters/OAR025/single-resource.json
    new file mode 100644
    index 00000000..3357f145
    --- /dev/null
    +++ b/src/test/resources/checks/v2/parameters/OAR025/single-resource.json
    @@ -0,0 +1,23 @@
    +{
    +  "swagger" : "2.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "type" : "string"
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v2/parameters/OAR025/single-resource.yaml b/src/test/resources/checks/v2/parameters/OAR025/single-resource.yaml
    new file mode 100644
    index 00000000..ae452772
    --- /dev/null
    +++ b/src/test/resources/checks/v2/parameters/OAR025/single-resource.yaml
    @@ -0,0 +1,14 @@
    +swagger: "2.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v2/resources/OAR017/plain.yaml b/src/test/resources/checks/v2/resources/OAR017/plain.yaml
    index 2a16af5a..08562325 100644
    --- a/src/test/resources/checks/v2/resources/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v2/resources/OAR017/plain.yaml
    @@ -61,3 +61,9 @@ paths:
           responses:
             200:
               description: Ok
    +
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: Ok
    diff --git a/src/test/resources/checks/v3/core/OAR044/media-type.json b/src/test/resources/checks/v3/core/OAR044/media-type.json
    index 992ea7bd..d954dc15 100644
    --- a/src/test/resources/checks/v3/core/OAR044/media-type.json
    +++ b/src/test/resources/checks/v3/core/OAR044/media-type.json
    @@ -34,9 +34,27 @@
             } ]
           },
           "post" : {
    +        "requestBody" : {
    +          "content" : {
    +            "application/vnd.ms-excel" : { },
    +            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +            "application/ld+json" : { },
    +            "image/*" : { },
    +            "*/*" : { }
    +          }
    +        },
             "responses" : {
               "200" : {
    -            "description" : "some operation"
    +            "description" : "some operation",
    +            "content" : {
    +              "application/json" : { },
    +              "text/csv" : { },
    +              "image/png" : { },
    +              "application/vnd.ms-excel" : { },
    +              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +              "application/vnd.github+json" : { },
    +              "text/plain; charset=utf-8" : { }
    +            }
               }
             }
           }
    diff --git a/src/test/resources/checks/v3/core/OAR044/media-type.yaml b/src/test/resources/checks/v3/core/OAR044/media-type.yaml
    index 80aba718..3b6ac527 100644
    --- a/src/test/resources/checks/v3/core/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v3/core/OAR044/media-type.yaml
    @@ -24,6 +24,21 @@ paths:
             - name: otherParam
               in: path
         post:
    +      requestBody:
    +        content:
    +          'application/vnd.ms-excel': {}
    +          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +          'application/ld+json': {}
    +          'image/*': {}
    +          '*/*': {}
           responses:
    -         '200':
    -           description: some operation
    +        '200':
    +          description: some operation
    +          content:
    +            'application/json': {}
    +            'text/csv': {}
    +            'image/png': {}
    +            'application/vnd.ms-excel': {}
    +            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +            'application/vnd.github+json': {}
    +            'text/plain; charset=utf-8': {}
    diff --git a/src/test/resources/checks/v3/examples/OAR031/externalref.yaml b/src/test/resources/checks/v3/examples/OAR031/externalref.yaml
    index 05e57ddb..e747a397 100644
    --- a/src/test/resources/checks/v3/examples/OAR031/externalref.yaml
    +++ b/src/test/resources/checks/v3/examples/OAR031/externalref.yaml
    @@ -14,7 +14,7 @@ paths:
           summary: Get all users
           description: Returns a list of users.
           responses:
    -        '200':
    +        '200': # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: A JSON array of user objects
               content:
                 application/json:
    @@ -40,7 +40,7 @@ paths:
                   name: Puppy
                   type: dog
           responses:
    -        '200':
    +        '200': # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: A single user object
               content:
                 application/json:
    diff --git a/src/test/resources/checks/v3/examples/OAR031/nested-properties-examples.yaml b/src/test/resources/checks/v3/examples/OAR031/nested-properties-examples.yaml
    index d80344b0..9a67dda1 100644
    --- a/src/test/resources/checks/v3/examples/OAR031/nested-properties-examples.yaml
    +++ b/src/test/resources/checks/v3/examples/OAR031/nested-properties-examples.yaml
    @@ -6,7 +6,7 @@ paths:
       /profile:
         put:
           summary: Update user profile
    -      requestBody:
    +      requestBody: # Noncompliant {{OAR031: Request body must have one or more examples defined}}
             required: true
             content:
               application/json:
    diff --git a/src/test/resources/checks/v3/format/OAR037/complete.json b/src/test/resources/checks/v3/format/OAR037/complete.json
    index b9e6416d..7c6f894f 100644
    --- a/src/test/resources/checks/v3/format/OAR037/complete.json
    +++ b/src/test/resources/checks/v3/format/OAR037/complete.json
    @@ -10,7 +10,7 @@
             "in": "header",
             "name": "paramOne",
             "schema": {
    -          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               "format": "YYYY-MM-DD"
             }
           },
    @@ -18,7 +18,7 @@
             "in": "header",
             "name": "paramTwo",
             "schema": {
    -          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               "format": "YYYY-MM-DD"
             }
           }
    @@ -34,7 +34,7 @@
               "in": "header",
               "name": "paramThree",
               "schema": {
    -            "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +            "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                 "format": "YYYY-MM-DD"
               }
             }
    @@ -54,7 +54,15 @@
                       "type": "object",
                       "properties": {
                         "without": {
    -                      "type": "string" # Noncompliant {{OAR037: String types requires a valid format}}
    +                      "type": "string" # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    },
    +                    "withPattern": {
    +                      "type": "string",
    +                      "pattern": "^[A-Z]{3}-[0-9]+$"
    +                    },
    +                    "withInvalidPattern": {
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                      "pattern": "["
                         },
                         "date": {
                           "type": "string",
    @@ -101,7 +109,7 @@
                           "format": "ipv6"
                         },
                         "other": {
    -                      "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                           "format": "YYYY-MM-DD"
                         }
                       }
    diff --git a/src/test/resources/checks/v3/format/OAR037/complete.yaml b/src/test/resources/checks/v3/format/OAR037/complete.yaml
    index 2120e544..0008a528 100644
    --- a/src/test/resources/checks/v3/format/OAR037/complete.yaml
    +++ b/src/test/resources/checks/v3/format/OAR037/complete.yaml
    @@ -8,13 +8,13 @@ components:
           in: header
           name: paramOne
           schema:
    -        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
             format: YYYY-MM-DD
         paramTwo:
           in: header
           name: paramTwo
           schema:
    -        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
             format: YYYY-MM-DD
     paths:
       /invoices:
    @@ -23,7 +23,7 @@ paths:
           - in: header
             name: paramThree
             schema:
    -          type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +          type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               format: YYYY-MM-DD
         get:
           parameters:
    @@ -37,7 +37,13 @@ paths:
                     type: object
                     properties:
                       without:
    -                    type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                  withPattern:
    +                    type: string
    +                    pattern: '^[A-Z]{3}-[0-9]+$'
    +                  withInvalidPattern:
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    pattern: '['
                       date:
                         type: string
                         format: date
    @@ -72,5 +78,5 @@ paths:
                         type: string
                         format: ipv6
                       other:
    -                    type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                         format: YYYY-MM-DD
    diff --git a/src/test/resources/checks/v3/format/OAR037/nested.json b/src/test/resources/checks/v3/format/OAR037/nested.json
    index 4b6316e6..5f6a71dc 100644
    --- a/src/test/resources/checks/v3/format/OAR037/nested.json
    +++ b/src/test/resources/checks/v3/format/OAR037/nested.json
    @@ -19,8 +19,12 @@
                           "type": "object",
                           "properties": {
                             "value": {
    -                          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                               "format": "YYYY-MM-DD"
    +                        },
    +                        "code": {
    +                          "type": "string",
    +                          "pattern": "^[A-Z]{3}-[0-9]+$"
                             }
                           }
                         }
    diff --git a/src/test/resources/checks/v3/format/OAR037/nested.yaml b/src/test/resources/checks/v3/format/OAR037/nested.yaml
    index e2ba0a91..9a0465f1 100644
    --- a/src/test/resources/checks/v3/format/OAR037/nested.yaml
    +++ b/src/test/resources/checks/v3/format/OAR037/nested.yaml
    @@ -17,6 +17,9 @@ paths:
                         type: object
                         properties:
                           value:
    -                        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                             format: YYYY-MM-DD
    +                      code:
    +                        type: string
    +                        pattern: '^[A-Z]{3}-[0-9]+$'
     
    diff --git a/src/test/resources/checks/v3/format/OAR037/no-format.json b/src/test/resources/checks/v3/format/OAR037/no-format.json
    new file mode 100644
    index 00000000..57a1dd0f
    --- /dev/null
    +++ b/src/test/resources/checks/v3/format/OAR037/no-format.json
    @@ -0,0 +1,42 @@
    +{
    +  "openapi": "3.0.0",
    +  "info": {
    +    "version": "1.0.0",
    +    "title": "Swagger Petstore"
    +  },
    +  "paths": {
    +    "/invoices": {
    +      "get": {
    +        "responses": {
    +          "200": {
    +            "description": "A invoice.",
    +            "content": {
    +              "application/json": {
    +                "schema": {
    +                  "type": "object",
    +                  "properties": {
    +                    "name": {
    +                      "type": "string",
    +                      "pattern": "^[A-Za-z ]+$"
    +                    },
    +                    "emptyPattern": {
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                      "pattern": ""
    +                    },
    +                    "invalidPattern": {
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                      "pattern": "[a-z"
    +                    },
    +                    "code": {
    +                      "type": "string" # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    }
    +                  }
    +                }
    +              }
    +            }
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v3/format/OAR037/no-format.yaml b/src/test/resources/checks/v3/format/OAR037/no-format.yaml
    new file mode 100644
    index 00000000..ec4f21f1
    --- /dev/null
    +++ b/src/test/resources/checks/v3/format/OAR037/no-format.yaml
    @@ -0,0 +1,26 @@
    +openapi: "3.0.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /invoices:
    +    get:
    +      responses:
    +        200:
    +          description: A invoice.
    +          content:
    +            application/json:
    +              schema:
    +                type: object
    +                properties:
    +                  name:
    +                    type: string
    +                    pattern: '^[A-Za-z ]+$'
    +                  emptyPattern:
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    pattern: ""
    +                  invalidPattern:
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    pattern: "[a-z"
    +                  code:
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    diff --git a/src/test/resources/checks/v3/format/OAR037/with-$ref.json b/src/test/resources/checks/v3/format/OAR037/with-$ref.json
    index 5707bfcb..51e70ff3 100644
    --- a/src/test/resources/checks/v3/format/OAR037/with-$ref.json
    +++ b/src/test/resources/checks/v3/format/OAR037/with-$ref.json
    @@ -37,8 +37,12 @@
             "type": "object",
             "properties": {
               "value": {
    -            "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +            "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                 "format": "YYYY-MM-DD"
    +          },
    +          "code": {
    +            "type": "string",
    +            "pattern": "^[A-Z]{3}-[0-9]+$"
               }
             }
           }
    diff --git a/src/test/resources/checks/v3/format/OAR037/with-$ref.yaml b/src/test/resources/checks/v3/format/OAR037/with-$ref.yaml
    index c7d2f1f4..fbe316a5 100644
    --- a/src/test/resources/checks/v3/format/OAR037/with-$ref.yaml
    +++ b/src/test/resources/checks/v3/format/OAR037/with-$ref.yaml
    @@ -25,5 +25,8 @@ components:
           type: object
           properties:
             value:
    -          type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +          type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               format: YYYY-MM-DD
    +        code:
    +          type: string
    +          pattern: '^[A-Z]{3}-[0-9]+$'
    diff --git a/src/test/resources/checks/v3/format/OAR044/media-type.json b/src/test/resources/checks/v3/format/OAR044/media-type.json
    index 89bd88b8..3d3b5d7a 100644
    --- a/src/test/resources/checks/v3/format/OAR044/media-type.json
    +++ b/src/test/resources/checks/v3/format/OAR044/media-type.json
    @@ -32,12 +32,26 @@
           "requestBody" : {
             "content" : {
               "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}}
    -          "text/*" : { }
    +          "text/*" : { },
    +          "application/vnd.ms-excel" : { },
    +          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +          "application/ld+json" : { },
    +          "image/*" : { },
    +          "*/*" : { }
               }
             },
             "responses" : {
               "200" : {
    -            "description" : "some operation"
    +            "description" : "some operation",
    +            "content" : {
    +              "application/json" : { },
    +              "text/csv" : { },
    +              "image/png" : { },
    +              "application/vnd.ms-excel" : { },
    +              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +              "application/vnd.github+json" : { },
    +              "text/plain; charset=utf-8" : { }
    +            }
               }
             }
           }
    diff --git a/src/test/resources/checks/v3/format/OAR044/media-type.yaml b/src/test/resources/checks/v3/format/OAR044/media-type.yaml
    index 46ffdc20..60d8c85a 100644
    --- a/src/test/resources/checks/v3/format/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v3/format/OAR044/media-type.yaml
    @@ -23,6 +23,19 @@ paths:
             content:
               'application': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}}
               'text/*': { }
    +          'application/vnd.ms-excel': {}
    +          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +          'application/ld+json': {}
    +          'image/*': {}
    +          '*/*': {}
           responses:
    -         '200':
    -           description: some operation
    +        '200':
    +          description: some operation
    +          content:
    +            'application/json': {}
    +            'text/csv': {}
    +            'image/png': {}
    +            'application/vnd.ms-excel': {}
    +            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +            'application/vnd.github+json': {}
    +            'text/plain; charset=utf-8': {}
    diff --git a/src/test/resources/checks/v3/operations/OAR017/plain.yaml b/src/test/resources/checks/v3/operations/OAR017/plain.yaml
    index d902e89e..298bd9f9 100644
    --- a/src/test/resources/checks/v3/operations/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v3/operations/OAR017/plain.yaml
    @@ -43,3 +43,8 @@ paths:
           responses:
             200:
               description: Ok
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: Ok
    diff --git a/src/test/resources/checks/v3/parameters/OAR019/excluded.yaml b/src/test/resources/checks/v3/parameters/OAR019/excluded.yaml
    index 7758deac..5bb25ac8 100644
    --- a/src/test/resources/checks/v3/parameters/OAR019/excluded.yaml
    +++ b/src/test/resources/checks/v3/parameters/OAR019/excluded.yaml
    @@ -3,7 +3,7 @@ info:
       version: 1.0.0
       title: Swagger Petstore
     paths:
    -  /another:
    +  /status:
         get:
           parameters:
             - in: query
    diff --git a/src/test/resources/checks/v3/parameters/OAR022/single-resource.json b/src/test/resources/checks/v3/parameters/OAR022/single-resource.json
    new file mode 100644
    index 00000000..54255ba9
    --- /dev/null
    +++ b/src/test/resources/checks/v3/parameters/OAR022/single-resource.json
    @@ -0,0 +1,25 @@
    +{
    +  "openapi" : "3.0.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "schema" : {
    +            "type" : "string"
    +          }
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v3/parameters/OAR022/single-resource.yaml b/src/test/resources/checks/v3/parameters/OAR022/single-resource.yaml
    new file mode 100644
    index 00000000..e76282c7
    --- /dev/null
    +++ b/src/test/resources/checks/v3/parameters/OAR022/single-resource.yaml
    @@ -0,0 +1,15 @@
    +openapi: "3.0.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          schema:
    +            type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v3/parameters/OAR025/single-resource.json b/src/test/resources/checks/v3/parameters/OAR025/single-resource.json
    new file mode 100644
    index 00000000..54255ba9
    --- /dev/null
    +++ b/src/test/resources/checks/v3/parameters/OAR025/single-resource.json
    @@ -0,0 +1,25 @@
    +{
    +  "openapi" : "3.0.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "schema" : {
    +            "type" : "string"
    +          }
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v3/parameters/OAR025/single-resource.yaml b/src/test/resources/checks/v3/parameters/OAR025/single-resource.yaml
    new file mode 100644
    index 00000000..e76282c7
    --- /dev/null
    +++ b/src/test/resources/checks/v3/parameters/OAR025/single-resource.yaml
    @@ -0,0 +1,15 @@
    +openapi: "3.0.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          schema:
    +            type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v3/resources/OAR017/plain.yaml b/src/test/resources/checks/v3/resources/OAR017/plain.yaml
    index f872fa73..189c4d50 100644
    --- a/src/test/resources/checks/v3/resources/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v3/resources/OAR017/plain.yaml
    @@ -56,3 +56,8 @@ paths:
           responses:
             200:
               description: Ok
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: Ok
    diff --git a/src/test/resources/checks/v31/core/OAR044/media-type.json b/src/test/resources/checks/v31/core/OAR044/media-type.json
    index 938aab91..2200bfd1 100644
    --- a/src/test/resources/checks/v31/core/OAR044/media-type.json
    +++ b/src/test/resources/checks/v31/core/OAR044/media-type.json
    @@ -34,9 +34,27 @@
             } ]
           },
           "post" : {
    +        "requestBody" : {
    +          "content" : {
    +            "application/vnd.ms-excel" : { },
    +            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +            "application/ld+json" : { },
    +            "image/*" : { },
    +            "*/*" : { }
    +          }
    +        },
             "responses" : {
               "200" : {
    -            "description" : "some operation"
    +            "description" : "some operation",
    +            "content" : {
    +              "application/json" : { },
    +              "text/csv" : { },
    +              "image/png" : { },
    +              "application/vnd.ms-excel" : { },
    +              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +              "application/vnd.github+json" : { },
    +              "text/plain; charset=utf-8" : { }
    +            }
               }
             }
           }
    diff --git a/src/test/resources/checks/v31/core/OAR044/media-type.yaml b/src/test/resources/checks/v31/core/OAR044/media-type.yaml
    index 67d72d30..23fe935e 100644
    --- a/src/test/resources/checks/v31/core/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v31/core/OAR044/media-type.yaml
    @@ -24,6 +24,21 @@ paths:
             - name: otherParam
               in: path
         post:
    +      requestBody:
    +        content:
    +          'application/vnd.ms-excel': {}
    +          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +          'application/ld+json': {}
    +          'image/*': {}
    +          '*/*': {}
           responses:
    -         '200':
    -           description: some operation
    +        '200':
    +          description: some operation
    +          content:
    +            'application/json': {}
    +            'text/csv': {}
    +            'image/png': {}
    +            'application/vnd.ms-excel': {}
    +            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +            'application/vnd.github+json': {}
    +            'text/plain; charset=utf-8': {}
    diff --git a/src/test/resources/checks/v31/examples/OAR031/externalref.yaml b/src/test/resources/checks/v31/examples/OAR031/externalref.yaml
    index 21cee27e..4e6e96e7 100644
    --- a/src/test/resources/checks/v31/examples/OAR031/externalref.yaml
    +++ b/src/test/resources/checks/v31/examples/OAR031/externalref.yaml
    @@ -14,7 +14,7 @@ paths:
           summary: Get all users
           description: Returns a list of users.
           responses:
    -        '200':
    +        '200': # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: A JSON array of user objects
               content:
                 application/json:
    @@ -40,7 +40,7 @@ paths:
                   name: Puppy
                   type: dog
           responses:
    -        '200':
    +        '200': # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: A single user object
               content:
                 application/json:
    diff --git a/src/test/resources/checks/v31/examples/OAR031/nested-properties-examples.yaml b/src/test/resources/checks/v31/examples/OAR031/nested-properties-examples.yaml
    index bf96e975..c48f0f18 100644
    --- a/src/test/resources/checks/v31/examples/OAR031/nested-properties-examples.yaml
    +++ b/src/test/resources/checks/v31/examples/OAR031/nested-properties-examples.yaml
    @@ -6,7 +6,7 @@ paths:
       /profile:
         put:
           summary: Update user profile
    -      requestBody:
    +      requestBody: # Noncompliant {{OAR031: Request body must have one or more examples defined}}
             required: true
             content:
               application/json:
    diff --git a/src/test/resources/checks/v31/format/OAR037/complete.json b/src/test/resources/checks/v31/format/OAR037/complete.json
    index 8c943299..6584f397 100644
    --- a/src/test/resources/checks/v31/format/OAR037/complete.json
    +++ b/src/test/resources/checks/v31/format/OAR037/complete.json
    @@ -10,7 +10,7 @@
             "in": "header",
             "name": "paramOne",
             "schema": {
    -          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               "format": "YYYY-MM-DD"
             }
           },
    @@ -18,7 +18,7 @@
             "in": "header",
             "name": "paramTwo",
             "schema": {
    -          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               "format": "YYYY-MM-DD"
             }
           }
    @@ -34,7 +34,7 @@
               "in": "header",
               "name": "paramThree",
               "schema": {
    -            "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +            "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                 "format": "YYYY-MM-DD"
               }
             }
    @@ -54,7 +54,15 @@
                       "type": "object",
                       "properties": {
                         "without": {
    -                      "type": "string" # Noncompliant {{OAR037: String types requires a valid format}}
    +                      "type": "string" # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    },
    +                    "withPattern": {
    +                      "type": "string",
    +                      "pattern": "^[A-Z]{3}-[0-9]+$"
    +                    },
    +                    "withInvalidPattern": {
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                      "pattern": "["
                         },
                         "date": {
                           "type": "string",
    @@ -101,7 +109,7 @@
                           "format": "ipv6"
                         },
                         "other": {
    -                      "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                           "format": "YYYY-MM-DD"
                         }
                       }
    diff --git a/src/test/resources/checks/v31/format/OAR037/complete.yaml b/src/test/resources/checks/v31/format/OAR037/complete.yaml
    index 769a4793..e75afc02 100644
    --- a/src/test/resources/checks/v31/format/OAR037/complete.yaml
    +++ b/src/test/resources/checks/v31/format/OAR037/complete.yaml
    @@ -8,13 +8,13 @@ components:
           in: header
           name: paramOne
           schema:
    -        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
             format: YYYY-MM-DD
         paramTwo:
           in: header
           name: paramTwo
           schema:
    -        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
             format: YYYY-MM-DD
     paths:
       /invoices:
    @@ -23,7 +23,7 @@ paths:
           - in: header
             name: paramThree
             schema:
    -          type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +          type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               format: YYYY-MM-DD
         get:
           parameters:
    @@ -37,7 +37,13 @@ paths:
                     type: object
                     properties:
                       without:
    -                    type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                  withPattern:
    +                    type: string
    +                    pattern: '^[A-Z]{3}-[0-9]+$'
    +                  withInvalidPattern:
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    pattern: '['
                       date:
                         type: string
                         format: date
    @@ -72,5 +78,5 @@ paths:
                         type: string
                         format: ipv6
                       other:
    -                    type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                         format: YYYY-MM-DD
    diff --git a/src/test/resources/checks/v31/format/OAR037/nested.json b/src/test/resources/checks/v31/format/OAR037/nested.json
    index 7d632201..5fc02cb9 100644
    --- a/src/test/resources/checks/v31/format/OAR037/nested.json
    +++ b/src/test/resources/checks/v31/format/OAR037/nested.json
    @@ -19,8 +19,12 @@
                           "type": "object",
                           "properties": {
                             "value": {
    -                          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                               "format": "YYYY-MM-DD"
    +                        },
    +                        "code": {
    +                          "type": "string",
    +                          "pattern": "^[A-Z]{3}-[0-9]+$"
                             }
                           }
                         }
    diff --git a/src/test/resources/checks/v31/format/OAR037/nested.yaml b/src/test/resources/checks/v31/format/OAR037/nested.yaml
    index 4a1accb7..302751f2 100644
    --- a/src/test/resources/checks/v31/format/OAR037/nested.yaml
    +++ b/src/test/resources/checks/v31/format/OAR037/nested.yaml
    @@ -17,6 +17,9 @@ paths:
                         type: object
                         properties:
                           value:
    -                        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                             format: YYYY-MM-DD
    +                      code:
    +                        type: string
    +                        pattern: '^[A-Z]{3}-[0-9]+$'
     
    diff --git a/src/test/resources/checks/v31/format/OAR037/with-$ref.json b/src/test/resources/checks/v31/format/OAR037/with-$ref.json
    index d5ed29ea..0e0d12bc 100644
    --- a/src/test/resources/checks/v31/format/OAR037/with-$ref.json
    +++ b/src/test/resources/checks/v31/format/OAR037/with-$ref.json
    @@ -37,8 +37,12 @@
             "type": "object",
             "properties": {
               "value": {
    -            "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +            "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                 "format": "YYYY-MM-DD"
    +          },
    +          "code": {
    +            "type": "string",
    +            "pattern": "^[A-Z]{3}-[0-9]+$"
               }
             }
           }
    diff --git a/src/test/resources/checks/v31/format/OAR037/with-$ref.yaml b/src/test/resources/checks/v31/format/OAR037/with-$ref.yaml
    index b6437060..36a92461 100644
    --- a/src/test/resources/checks/v31/format/OAR037/with-$ref.yaml
    +++ b/src/test/resources/checks/v31/format/OAR037/with-$ref.yaml
    @@ -25,5 +25,8 @@ components:
           type: object
           properties:
             value:
    -          type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +          type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               format: YYYY-MM-DD
    +        code:
    +          type: string
    +          pattern: '^[A-Z]{3}-[0-9]+$'
    diff --git a/src/test/resources/checks/v31/format/OAR044/media-type.json b/src/test/resources/checks/v31/format/OAR044/media-type.json
    index 86ec986a..05232934 100644
    --- a/src/test/resources/checks/v31/format/OAR044/media-type.json
    +++ b/src/test/resources/checks/v31/format/OAR044/media-type.json
    @@ -32,12 +32,26 @@
           "requestBody" : {
             "content" : {
               "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}}
    -          "text/*" : { }
    +          "text/*" : { },
    +          "application/vnd.ms-excel" : { },
    +          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +          "application/ld+json" : { },
    +          "image/*" : { },
    +          "*/*" : { }
               }
             },
             "responses" : {
               "200" : {
    -            "description" : "some operation"
    +            "description" : "some operation",
    +            "content" : {
    +              "application/json" : { },
    +              "text/csv" : { },
    +              "image/png" : { },
    +              "application/vnd.ms-excel" : { },
    +              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +              "application/vnd.github+json" : { },
    +              "text/plain; charset=utf-8" : { }
    +            }
               }
             }
           }
    diff --git a/src/test/resources/checks/v31/format/OAR044/media-type.yaml b/src/test/resources/checks/v31/format/OAR044/media-type.yaml
    index 60015c9b..71f903d8 100644
    --- a/src/test/resources/checks/v31/format/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v31/format/OAR044/media-type.yaml
    @@ -23,6 +23,19 @@ paths:
             content:
               'application': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}}
               'text/*': { }
    +          'application/vnd.ms-excel': {}
    +          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +          'application/ld+json': {}
    +          'image/*': {}
    +          '*/*': {}
           responses:
    -         '200':
    -           description: some operation
    +        '200':
    +          description: some operation
    +          content:
    +            'application/json': {}
    +            'text/csv': {}
    +            'image/png': {}
    +            'application/vnd.ms-excel': {}
    +            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +            'application/vnd.github+json': {}
    +            'text/plain; charset=utf-8': {}
    diff --git a/src/test/resources/checks/v31/operations/OAR017/plain.yaml b/src/test/resources/checks/v31/operations/OAR017/plain.yaml
    index 72bb577e..9ad95cf0 100644
    --- a/src/test/resources/checks/v31/operations/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v31/operations/OAR017/plain.yaml
    @@ -43,3 +43,8 @@ paths:
           responses:
             200:
               description: Ok
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: Ok
    diff --git a/src/test/resources/checks/v31/parameters/OAR019/excluded.yaml b/src/test/resources/checks/v31/parameters/OAR019/excluded.yaml
    index 8a1c820c..67391c40 100644
    --- a/src/test/resources/checks/v31/parameters/OAR019/excluded.yaml
    +++ b/src/test/resources/checks/v31/parameters/OAR019/excluded.yaml
    @@ -3,7 +3,7 @@ info:
       version: 1.0.0
       title: Swagger Petstore
     paths:
    -  /another:
    +  /status:
         get:
           parameters:
             - in: query
    diff --git a/src/test/resources/checks/v31/parameters/OAR022/single-resource.json b/src/test/resources/checks/v31/parameters/OAR022/single-resource.json
    new file mode 100644
    index 00000000..68f78709
    --- /dev/null
    +++ b/src/test/resources/checks/v31/parameters/OAR022/single-resource.json
    @@ -0,0 +1,25 @@
    +{
    +  "openapi" : "3.1.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "schema" : {
    +            "type" : "string"
    +          }
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v31/parameters/OAR022/single-resource.yaml b/src/test/resources/checks/v31/parameters/OAR022/single-resource.yaml
    new file mode 100644
    index 00000000..6e692751
    --- /dev/null
    +++ b/src/test/resources/checks/v31/parameters/OAR022/single-resource.yaml
    @@ -0,0 +1,15 @@
    +openapi: "3.1.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          schema:
    +            type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v31/parameters/OAR025/single-resource.json b/src/test/resources/checks/v31/parameters/OAR025/single-resource.json
    new file mode 100644
    index 00000000..68f78709
    --- /dev/null
    +++ b/src/test/resources/checks/v31/parameters/OAR025/single-resource.json
    @@ -0,0 +1,25 @@
    +{
    +  "openapi" : "3.1.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "schema" : {
    +            "type" : "string"
    +          }
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v31/parameters/OAR025/single-resource.yaml b/src/test/resources/checks/v31/parameters/OAR025/single-resource.yaml
    new file mode 100644
    index 00000000..6e692751
    --- /dev/null
    +++ b/src/test/resources/checks/v31/parameters/OAR025/single-resource.yaml
    @@ -0,0 +1,15 @@
    +openapi: "3.1.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          schema:
    +            type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v31/resources/OAR017/plain.yaml b/src/test/resources/checks/v31/resources/OAR017/plain.yaml
    index 87dee561..674c3d0c 100644
    --- a/src/test/resources/checks/v31/resources/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v31/resources/OAR017/plain.yaml
    @@ -56,3 +56,9 @@ paths:
           responses:
             200:
               description: Ok
    +
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: Ok
    diff --git a/src/test/resources/checks/v32/core/OAR044/media-type.json b/src/test/resources/checks/v32/core/OAR044/media-type.json
    index 517db4d8..9b7f036f 100644
    --- a/src/test/resources/checks/v32/core/OAR044/media-type.json
    +++ b/src/test/resources/checks/v32/core/OAR044/media-type.json
    @@ -34,9 +34,27 @@
             } ]
           },
           "post" : {
    +        "requestBody" : {
    +          "content" : {
    +            "application/vnd.ms-excel" : { },
    +            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +            "application/ld+json" : { },
    +            "image/*" : { },
    +            "*/*" : { }
    +          }
    +        },
             "responses" : {
               "200" : {
    -            "description" : "some operation"
    +            "description" : "some operation",
    +            "content" : {
    +              "application/json" : { },
    +              "text/csv" : { },
    +              "image/png" : { },
    +              "application/vnd.ms-excel" : { },
    +              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +              "application/vnd.github+json" : { },
    +              "text/plain; charset=utf-8" : { }
    +            }
               }
             }
           }
    diff --git a/src/test/resources/checks/v32/core/OAR044/media-type.yaml b/src/test/resources/checks/v32/core/OAR044/media-type.yaml
    index 22b32de1..bde8534c 100644
    --- a/src/test/resources/checks/v32/core/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v32/core/OAR044/media-type.yaml
    @@ -24,6 +24,21 @@ paths:
             - name: otherParam
               in: path
         post:
    +      requestBody:
    +        content:
    +          'application/vnd.ms-excel': {}
    +          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +          'application/ld+json': {}
    +          'image/*': {}
    +          '*/*': {}
           responses:
    -         '200':
    -           description: some operation
    +        '200':
    +          description: some operation
    +          content:
    +            'application/json': {}
    +            'text/csv': {}
    +            'image/png': {}
    +            'application/vnd.ms-excel': {}
    +            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +            'application/vnd.github+json': {}
    +            'text/plain; charset=utf-8': {}
    diff --git a/src/test/resources/checks/v32/examples/OAR031/externalref.yaml b/src/test/resources/checks/v32/examples/OAR031/externalref.yaml
    index 126feb8a..2c326a8b 100644
    --- a/src/test/resources/checks/v32/examples/OAR031/externalref.yaml
    +++ b/src/test/resources/checks/v32/examples/OAR031/externalref.yaml
    @@ -14,7 +14,7 @@ paths:
           summary: Get all users
           description: Returns a list of users.
           responses:
    -        '200':
    +        '200': # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: A JSON array of user objects
               content:
                 application/json:
    @@ -40,7 +40,7 @@ paths:
                   name: Puppy
                   type: dog
           responses:
    -        '200':
    +        '200': # Noncompliant {{OAR031: Responses must have one or more examples defined}}
               description: A single user object
               content:
                 application/json:
    diff --git a/src/test/resources/checks/v32/examples/OAR031/nested-properties-examples.yaml b/src/test/resources/checks/v32/examples/OAR031/nested-properties-examples.yaml
    index 34233555..e93c96a9 100644
    --- a/src/test/resources/checks/v32/examples/OAR031/nested-properties-examples.yaml
    +++ b/src/test/resources/checks/v32/examples/OAR031/nested-properties-examples.yaml
    @@ -6,7 +6,7 @@ paths:
       /profile:
         put:
           summary: Update user profile
    -      requestBody:
    +      requestBody: # Noncompliant {{OAR031: Request body must have one or more examples defined}}
             required: true
             content:
               application/json:
    diff --git a/src/test/resources/checks/v32/format/OAR037/complete.json b/src/test/resources/checks/v32/format/OAR037/complete.json
    index 4b9f4508..74f1adcd 100644
    --- a/src/test/resources/checks/v32/format/OAR037/complete.json
    +++ b/src/test/resources/checks/v32/format/OAR037/complete.json
    @@ -10,7 +10,7 @@
             "in": "header",
             "name": "paramOne",
             "schema": {
    -          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               "format": "YYYY-MM-DD"
             }
           },
    @@ -18,7 +18,7 @@
             "in": "header",
             "name": "paramTwo",
             "schema": {
    -          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               "format": "YYYY-MM-DD"
             }
           }
    @@ -34,7 +34,7 @@
               "in": "header",
               "name": "paramThree",
               "schema": {
    -            "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +            "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                 "format": "YYYY-MM-DD"
               }
             }
    @@ -54,7 +54,15 @@
                       "type": "object",
                       "properties": {
                         "without": {
    -                      "type": "string" # Noncompliant {{OAR037: String types requires a valid format}}
    +                      "type": "string" # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    },
    +                    "withPattern": {
    +                      "type": "string",
    +                      "pattern": "^[A-Z]{3}-[0-9]+$"
    +                    },
    +                    "withInvalidPattern": {
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                      "pattern": "["
                         },
                         "date": {
                           "type": "string",
    @@ -101,7 +109,7 @@
                           "format": "ipv6"
                         },
                         "other": {
    -                      "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                      "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                           "format": "YYYY-MM-DD"
                         }
                       }
    diff --git a/src/test/resources/checks/v32/format/OAR037/complete.yaml b/src/test/resources/checks/v32/format/OAR037/complete.yaml
    index 2be1bfa4..0e7f4cc7 100644
    --- a/src/test/resources/checks/v32/format/OAR037/complete.yaml
    +++ b/src/test/resources/checks/v32/format/OAR037/complete.yaml
    @@ -8,13 +8,13 @@ components:
           in: header
           name: paramOne
           schema:
    -        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
             format: YYYY-MM-DD
         paramTwo:
           in: header
           name: paramTwo
           schema:
    -        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
             format: YYYY-MM-DD
     paths:
       /invoices:
    @@ -23,7 +23,7 @@ paths:
           - in: header
             name: paramThree
             schema:
    -          type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +          type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               format: YYYY-MM-DD
         get:
           parameters:
    @@ -37,7 +37,13 @@ paths:
                     type: object
                     properties:
                       without:
    -                    type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                  withPattern:
    +                    type: string
    +                    pattern: '^[A-Z]{3}-[0-9]+$'
    +                  withInvalidPattern:
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
    +                    pattern: '['
                       date:
                         type: string
                         format: date
    @@ -72,5 +78,5 @@ paths:
                         type: string
                         format: ipv6
                       other:
    -                    type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                    type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                         format: YYYY-MM-DD
    diff --git a/src/test/resources/checks/v32/format/OAR037/nested.json b/src/test/resources/checks/v32/format/OAR037/nested.json
    index 08aa7e31..74e72c00 100644
    --- a/src/test/resources/checks/v32/format/OAR037/nested.json
    +++ b/src/test/resources/checks/v32/format/OAR037/nested.json
    @@ -19,8 +19,12 @@
                           "type": "object",
                           "properties": {
                             "value": {
    -                          "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +                          "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                               "format": "YYYY-MM-DD"
    +                        },
    +                        "code": {
    +                          "type": "string",
    +                          "pattern": "^[A-Z]{3}-[0-9]+$"
                             }
                           }
                         }
    diff --git a/src/test/resources/checks/v32/format/OAR037/nested.yaml b/src/test/resources/checks/v32/format/OAR037/nested.yaml
    index 8a2d2c6b..a6fd15be 100644
    --- a/src/test/resources/checks/v32/format/OAR037/nested.yaml
    +++ b/src/test/resources/checks/v32/format/OAR037/nested.yaml
    @@ -17,6 +17,9 @@ paths:
                         type: object
                         properties:
                           value:
    -                        type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +                        type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                             format: YYYY-MM-DD
    +                      code:
    +                        type: string
    +                        pattern: '^[A-Z]{3}-[0-9]+$'
     
    diff --git a/src/test/resources/checks/v32/format/OAR037/with-$ref.json b/src/test/resources/checks/v32/format/OAR037/with-$ref.json
    index d88ad1bc..0589c17f 100644
    --- a/src/test/resources/checks/v32/format/OAR037/with-$ref.json
    +++ b/src/test/resources/checks/v32/format/OAR037/with-$ref.json
    @@ -37,8 +37,12 @@
             "type": "object",
             "properties": {
               "value": {
    -            "type": "string", # Noncompliant {{OAR037: String types requires a valid format}}
    +            "type": "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
                 "format": "YYYY-MM-DD"
    +          },
    +          "code": {
    +            "type": "string",
    +            "pattern": "^[A-Z]{3}-[0-9]+$"
               }
             }
           }
    diff --git a/src/test/resources/checks/v32/format/OAR037/with-$ref.yaml b/src/test/resources/checks/v32/format/OAR037/with-$ref.yaml
    index 40f2fc10..b631e251 100644
    --- a/src/test/resources/checks/v32/format/OAR037/with-$ref.yaml
    +++ b/src/test/resources/checks/v32/format/OAR037/with-$ref.yaml
    @@ -25,5 +25,8 @@ components:
           type: object
           properties:
             value:
    -          type: string # Noncompliant {{OAR037: String types requires a valid format}}
    +          type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
               format: YYYY-MM-DD
    +        code:
    +          type: string
    +          pattern: '^[A-Z]{3}-[0-9]+$'
    diff --git a/src/test/resources/checks/v32/format/OAR044/media-type.json b/src/test/resources/checks/v32/format/OAR044/media-type.json
    index a37e77ee..0251e212 100644
    --- a/src/test/resources/checks/v32/format/OAR044/media-type.json
    +++ b/src/test/resources/checks/v32/format/OAR044/media-type.json
    @@ -32,12 +32,26 @@
           "requestBody" : {
             "content" : {
               "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}}
    -          "text/*" : { }
    +          "text/*" : { },
    +          "application/vnd.ms-excel" : { },
    +          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +          "application/ld+json" : { },
    +          "image/*" : { },
    +          "*/*" : { }
               }
             },
             "responses" : {
               "200" : {
    -            "description" : "some operation"
    +            "description" : "some operation",
    +            "content" : {
    +              "application/json" : { },
    +              "text/csv" : { },
    +              "image/png" : { },
    +              "application/vnd.ms-excel" : { },
    +              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { },
    +              "application/vnd.github+json" : { },
    +              "text/plain; charset=utf-8" : { }
    +            }
               }
             }
           }
    diff --git a/src/test/resources/checks/v32/format/OAR044/media-type.yaml b/src/test/resources/checks/v32/format/OAR044/media-type.yaml
    index 4dc3378b..6e1cbd7d 100644
    --- a/src/test/resources/checks/v32/format/OAR044/media-type.yaml
    +++ b/src/test/resources/checks/v32/format/OAR044/media-type.yaml
    @@ -23,6 +23,19 @@ paths:
             content:
               'application': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}}
               'text/*': { }
    +          'application/vnd.ms-excel': {}
    +          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +          'application/ld+json': {}
    +          'image/*': {}
    +          '*/*': {}
           responses:
    -         '200':
    -           description: some operation
    +        '200':
    +          description: some operation
    +          content:
    +            'application/json': {}
    +            'text/csv': {}
    +            'image/png': {}
    +            'application/vnd.ms-excel': {}
    +            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {}
    +            'application/vnd.github+json': {}
    +            'text/plain; charset=utf-8': {}
    diff --git a/src/test/resources/checks/v32/operations/OAR017/plain.yaml b/src/test/resources/checks/v32/operations/OAR017/plain.yaml
    index a623de5e..8c115f7b 100644
    --- a/src/test/resources/checks/v32/operations/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v32/operations/OAR017/plain.yaml
    @@ -43,3 +43,8 @@ paths:
           responses:
             200:
               description: Ok
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: Ok
    diff --git a/src/test/resources/checks/v32/parameters/OAR019/excluded.yaml b/src/test/resources/checks/v32/parameters/OAR019/excluded.yaml
    index 8a15d474..387db41b 100644
    --- a/src/test/resources/checks/v32/parameters/OAR019/excluded.yaml
    +++ b/src/test/resources/checks/v32/parameters/OAR019/excluded.yaml
    @@ -3,7 +3,7 @@ info:
       version: 1.0.0
       title: Swagger Petstore
     paths:
    -  /another:
    +  /status:
         get:
           parameters:
             - in: query
    diff --git a/src/test/resources/checks/v32/parameters/OAR022/single-resource.json b/src/test/resources/checks/v32/parameters/OAR022/single-resource.json
    new file mode 100644
    index 00000000..d08f568f
    --- /dev/null
    +++ b/src/test/resources/checks/v32/parameters/OAR022/single-resource.json
    @@ -0,0 +1,25 @@
    +{
    +  "openapi" : "3.2.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "schema" : {
    +            "type" : "string"
    +          }
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v32/parameters/OAR022/single-resource.yaml b/src/test/resources/checks/v32/parameters/OAR022/single-resource.yaml
    new file mode 100644
    index 00000000..b2a320f5
    --- /dev/null
    +++ b/src/test/resources/checks/v32/parameters/OAR022/single-resource.yaml
    @@ -0,0 +1,15 @@
    +openapi: "3.2.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          schema:
    +            type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v32/parameters/OAR025/single-resource.json b/src/test/resources/checks/v32/parameters/OAR025/single-resource.json
    new file mode 100644
    index 00000000..d08f568f
    --- /dev/null
    +++ b/src/test/resources/checks/v32/parameters/OAR025/single-resource.json
    @@ -0,0 +1,25 @@
    +{
    +  "openapi" : "3.2.0",
    +  "info" : {
    +    "version" : "1.0.0",
    +    "title" : "Swagger Petstore"
    +  },
    +  "paths" : {
    +    "/examples/{id}" : {
    +      "get" : {
    +        "parameters" : [ {
    +          "in" : "query",
    +          "name" : "other",
    +          "schema" : {
    +            "type" : "string"
    +          }
    +        } ],
    +        "responses" : {
    +          "206" : {
    +            "description" : "Ok"
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    diff --git a/src/test/resources/checks/v32/parameters/OAR025/single-resource.yaml b/src/test/resources/checks/v32/parameters/OAR025/single-resource.yaml
    new file mode 100644
    index 00000000..b2a320f5
    --- /dev/null
    +++ b/src/test/resources/checks/v32/parameters/OAR025/single-resource.yaml
    @@ -0,0 +1,15 @@
    +openapi: "3.2.0"
    +info:
    +  version: 1.0.0
    +  title: Swagger Petstore
    +paths:
    +  /examples/{id}:
    +    get:
    +      parameters:
    +        - in: query
    +          name: other
    +          schema:
    +            type: string
    +      responses:
    +        206:
    +          description: Ok
    diff --git a/src/test/resources/checks/v32/resources/OAR017/plain.yaml b/src/test/resources/checks/v32/resources/OAR017/plain.yaml
    index d3e714b9..baa25013 100644
    --- a/src/test/resources/checks/v32/resources/OAR017/plain.yaml
    +++ b/src/test/resources/checks/v32/resources/OAR017/plain.yaml
    @@ -56,3 +56,9 @@ paths:
           responses:
             200:
               description: Ok
    +
    +  /one/delete:
    +    post:
    +      responses:
    +        200:
    +          description: Ok