diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 6031fcd7..6c484687 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -13,14 +13,20 @@ jobs: steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for SonarCloud to get full git history - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' cache: maven - - name: Build with Maven - run: mvn -B package --file pom.xml + - name: Build, Test and Coverage + run: mvn -B verify --file pom.xml + - name: SonarCloud Analysis + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: mvn sonar:sonar -Dsonar.token=$SONAR_TOKEN # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - name: Update dependency graph diff --git a/CHANGELOG.md b/CHANGELOG.md index f28ae6eb..3ce9b595 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ 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.3.4] - 2026-04-01 + +### Fixed + - OAR029 - StandardResponseSchemaCheck Test + - OAR080 - SecuritySchemasCheck Test + - OAR112 - RegexCheck Test + + - OpenAPICustomPlugin Test + - OpenAPICustomProfileDefinition Test + - OpenAPICustomRuleRepository Test + - OpenAPICustomRulesDefinition Test + ## [1.3.3] - 2026-03-20 ### Fixed diff --git a/README.md b/README.md index bdd2aba7..f7d3d3fa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# 🛠️ sonaropenapi-rules ![Release](https://img.shields.io/badge/release-1.2.1-purple) ![Java](https://img.shields.io/badge/java-%23ED8B00.svg?style=flat&logo=openjdk&logoColor=white) [![License: LGPL v3](https://img.shields.io/badge/license-LGPL_v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) +# 🛠️ sonaropenapi-rules ![Release](https://img.shields.io/badge/release-1.3.4-purple) ![Java](https://img.shields.io/badge/java-%23ED8B00.svg?style=flat&logo=openjdk&logoColor=white) [![License: LGPL v3](https://img.shields.io/badge/license-LGPL_v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) This repository contains a set of custom SonarQube rules specifically designed to analyze and improve the quality of OpenAPI specifications. By integrating these rules, teams can ensure best practices, maintainability, and consistency in their API definitions. diff --git a/pom.xml b/pom.xml index 066499b6..1c899a46 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.apiaddicts.apitools.dosonarapi sonaropenapi-rules-community - 1.3.3 + 1.3.4 sonar-plugin SonarQube OpenAPI Community Rules @@ -71,9 +71,12 @@ 3.22.0 0.8.6 - 3.7.0.1746 + 5.5.0.6356 jacoco - ${project.basedir}/../target/jacoco.exec + ${project.basedir}/target/site/jacoco/jacoco.xml + https://sonarcloud.io + apiaddicts + apiaddicts_sonaropenapi-rules java **/*.html,**/*.json **/*.html,**/*.json @@ -264,14 +267,16 @@ + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar.maven.plugin.version} + + org.jacoco jacoco-maven-plugin ${jacoco.maven.plugin.version} - - ${sonar.jacoco.reportPaths} - true - agent @@ -279,6 +284,13 @@ prepare-agent + + report + verify + + report + + diff --git a/sonar-project.properties b/sonar-project.properties index b7aaefd4..77784ec9 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,3 +1,6 @@ +sonar.host.url=https://sonarcloud.io +sonar.organization=apiaddicts +sonar.projectKey=apiaddicts_sonaropenapi-rules sonar.sources=. sonar.exclusions=**/*.html,**/*.json sonar.cpd.exclusions=**/*.html,**/*.json \ No newline at end of file diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/schemas/OAR080SecuritySchemasCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/schemas/OAR080SecuritySchemasCheck.java index b3021139..6b22172d 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/schemas/OAR080SecuritySchemasCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/schemas/OAR080SecuritySchemasCheck.java @@ -49,7 +49,7 @@ public Set subscribedKinds() { @Override protected void visitFile(JsonNode root) { JsonNode security = root.get("security"); - hasGlobalSecurity = !(security.isMissing() || security.isNull() || security.elements().isEmpty()); + hasGlobalSecurity = !(security.isMissing() || security.elements().isEmpty()); expectedSecuritySchemes = Arrays.stream(expectedSecurityScheme.split(",")) .map(String::trim) @@ -61,11 +61,7 @@ protected void visitFile(JsonNode root) { @Override public void visitNode(JsonNode node) { if (hasGlobalSecurity) return; - - if (node.is(OpenApi2Grammar.PATH, OpenApi3Grammar.PATH, OpenApi31Grammar.PATH, - OpenApi2Grammar.OPERATION, OpenApi3Grammar.OPERATION, OpenApi31Grammar.OPERATION)) { - visitOperationNode(node); - } + visitOperationNode(node); } private void visitOperationNode(JsonNode node) { @@ -75,7 +71,7 @@ private void visitOperationNode(JsonNode node) { } JsonNode security = node.get("security"); - if (security.isMissing() || security.isNull() || security.elements().isEmpty()) { + if (security.isMissing() || security.elements().isEmpty()) { addIssue(KEY, translate(MESSAGE), node.key()); return; } diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/security/AbstractPropertiesCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/security/AbstractPropertiesCheck.java deleted file mode 100644 index f02a75d9..00000000 --- a/src/main/java/apiaddicts/sonar/openapi/checks/security/AbstractPropertiesCheck.java +++ /dev/null @@ -1,36 +0,0 @@ -package apiaddicts.sonar.openapi.checks.security; - -import com.google.common.collect.ImmutableSet; -import com.sonar.sslr.api.AstNodeType; -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 apiaddicts.sonar.openapi.checks.BaseCheck; -import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode; - -import java.util.Set; - -public abstract class AbstractPropertiesCheck extends BaseCheck { - - @Override - public Set subscribedKinds() { - return ImmutableSet.of(OpenApi2Grammar.SCHEMA, OpenApi2Grammar.PARAMETER, OpenApi3Grammar.SCHEMA, OpenApi31Grammar.SCHEMA); - } - - @Override - public void visitNode(JsonNode node) { - visitV2Node(node); - } - - private void visitV2Node(JsonNode node) { - JsonNode propertiesNode = node.get("properties"); - String properties = propertiesNode.getTokenValue(); - JsonNode typeNode = node.get("type"); - String type = typeNode.getTokenValue(); - JsonNode formatNode = node.get("format"); - String format = formatNode.isMissing() ? null : formatNode.getTokenValue(); - validate(type, format, properties, typeNode, propertiesNode); - } - - public abstract void validate(String type, String format, String properties, JsonNode typeNode, JsonNode propertiesNode); -} diff --git a/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomPluginTest.java b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomPluginTest.java new file mode 100644 index 00000000..db247fca --- /dev/null +++ b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomPluginTest.java @@ -0,0 +1,31 @@ +package apiaddicts.sonar.openapi; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; +import org.sonar.api.Plugin; +import org.sonar.api.SonarEdition; +import org.sonar.api.SonarProduct; +import org.sonar.api.SonarQubeSide; +import org.sonar.api.SonarRuntime; +import org.sonar.api.utils.Version; + +public class OpenAPICustomPluginTest { + + @Test + public void testDefine() { + OpenAPICustomPlugin plugin = new OpenAPICustomPlugin(); + SonarRuntime runtime = new SonarRuntime() { + @Override public Version getApiVersion() { return Version.create(9, 9); } + @Override public SonarProduct getProduct() { return SonarProduct.SONARQUBE; } + @Override public SonarQubeSide getSonarQubeSide() { return SonarQubeSide.SERVER; } + @Override public SonarEdition getEdition() { return SonarEdition.COMMUNITY; } + }; + Plugin.Context context = new Plugin.Context(runtime); + plugin.define(context); + assertThat(context.getExtensions()).hasSize(3); + assertThat(context.getExtensions()).contains( + OpenAPICustomProfileDefinition.class, + OpenAPICustomRulesDefinition.class, + OpenAPICustomRuleRepository.class); + } +} diff --git a/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomProfileDefinitionTest.java b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomProfileDefinitionTest.java new file mode 100644 index 00000000..904cf042 --- /dev/null +++ b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomProfileDefinitionTest.java @@ -0,0 +1,26 @@ +package apiaddicts.sonar.openapi; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; +import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; +import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInQualityProfile; + +import apiaddicts.sonar.openapi.checks.RulesLists; + +public class OpenAPICustomProfileDefinitionTest { + + @Test + public void testDefine() { + I18nContext.setLang("en"); + OpenAPICustomProfileDefinition profileDefinition = new OpenAPICustomProfileDefinition(); + BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context(); + profileDefinition.define(context); + BuiltInQualityProfile profile = context.profile("openapi", OpenAPICustomProfileDefinition.MY_COMPANY_WAY); + assertThat(profile).isNotNull(); + assertThat(profile.language()).isEqualTo("openapi"); + assertThat(profile.name()).isEqualTo(OpenAPICustomProfileDefinition.MY_COMPANY_WAY); + + assertThat(profile.rules()).hasSize(RulesLists.getAllChecks().size() - 1); + assertThat(profile.rules().stream().noneMatch(r -> r.ruleKey().equals("OAR112"))).isTrue(); + } +} diff --git a/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomRuleRepositoryTest.java b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomRuleRepositoryTest.java new file mode 100644 index 00000000..180b70cd --- /dev/null +++ b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomRuleRepositoryTest.java @@ -0,0 +1,22 @@ +package apiaddicts.sonar.openapi; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; + +import apiaddicts.sonar.openapi.checks.RulesLists; + +public class OpenAPICustomRuleRepositoryTest { + + @Test + public void testRepositoryKey() { + OpenAPICustomRuleRepository repository = new OpenAPICustomRuleRepository(); + assertThat(repository.repositoryKey()).isEqualTo(OpenAPICustomRulesDefinition.REPOSITORY_KEY); + } + + @Test + public void testCheckClasses() { + OpenAPICustomRuleRepository repository = new OpenAPICustomRuleRepository(); + assertThat(repository.checkClasses()).isEqualTo(RulesLists.getAllChecks()); + assertThat(repository.checkClasses()).isNotEmpty(); + } +} diff --git a/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomRulesDefinitionTest.java b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomRulesDefinitionTest.java index 7c4714bc..e507fcb3 100644 --- a/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomRulesDefinitionTest.java +++ b/src/test/java/apiaddicts/sonar/openapi/OpenAPICustomRulesDefinitionTest.java @@ -1,6 +1,7 @@ package apiaddicts.sonar.openapi; import static org.assertj.core.api.Assertions.assertThat; +import java.lang.reflect.Method; import org.junit.Test; import org.sonar.api.server.rule.RulesDefinition; import org.sonar.api.server.rule.RulesDefinition.Repository; @@ -20,4 +21,32 @@ public void testRepository() { assertThat(repository.language()).isEqualTo("openapi"); assertThat(repository.rules()).hasSize(RulesLists.getAllChecks().size()); } + + @Test + public void testGetPathWithSpanishLanguage() throws Exception { + I18nContext.setLang("es"); + OpenAPICustomRulesDefinition rulesDefinition = new OpenAPICustomRulesDefinition(); + + Method method = OpenAPICustomRulesDefinition.class.getDeclaredMethod("getPath", String.class); + method.setAccessible(true); + String path = (String) method.invoke(rulesDefinition, "security"); + + assertThat(path).contains("/es/"); + } + + @Test + public void testMarkAsTemplateWithNonExistentRule() throws Exception { + I18nContext.setLang("en"); + OpenAPICustomRulesDefinition rulesDefinition = new OpenAPICustomRulesDefinition(); + RulesDefinition.Context context = new RulesDefinition.Context(); + RulesDefinition.NewRepository newRepo = context.createRepository("test-repo", "openapi").setName("Test"); + + Method method = OpenAPICustomRulesDefinition.class.getDeclaredMethod( + "markAsTemplate", RulesDefinition.NewRepository.class, String.class); + method.setAccessible(true); + method.invoke(rulesDefinition, newRepo, "NON_EXISTENT_RULE"); + + newRepo.done(); + assertThat(context.repository("test-repo").rules()).isEmpty(); + } } diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/regex/OAR112RegexCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/regex/OAR112RegexCheckTest.java index 2e48af14..924a317e 100644 --- a/src/test/java/apiaddicts/sonar/openapi/checks/regex/OAR112RegexCheckTest.java +++ b/src/test/java/apiaddicts/sonar/openapi/checks/regex/OAR112RegexCheckTest.java @@ -7,6 +7,8 @@ import org.sonar.api.server.rule.RuleParamType; import apiaddicts.sonar.openapi.BaseCheckTest; +import java.lang.reflect.Field; + public class OAR112RegexCheckTest extends BaseCheckTest { @Before @@ -17,6 +19,16 @@ public void init() { v3Path = getV3Path("regex"); } + private void setField(String fieldName, String value) { + try { + Field field = OAR112RegexCheck.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(check, value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Test public void verifyInV2() { verifyV2("plain"); @@ -27,6 +39,161 @@ public void verifyInV3() { verifyV3("plain"); } + @Test + public void verifyInfoDescriptionInvalidInV2() { + verifyV2("info-invalid"); + } + + @Test + public void verifyInfoDescriptionInvalidInV3() { + verifyV3("info-invalid"); + } + + @Test + public void verifyServersDescriptionValidInV3() { + setField("nodes", "servers/description"); + verifyV3("servers-valid"); + } + + @Test + public void verifyServersDescriptionInvalidInV3() { + setField("nodes", "servers/description"); + verifyV3("servers-invalid"); + } + + @Test + public void verifyOperationSummaryValidInV3() { + setField("nodes", "paths/get/summary"); + verifyV3("operation-valid"); + } + + @Test + public void verifyOperationSummaryInvalidInV3() { + setField("nodes", "paths/get/summary"); + verifyV3("operation-invalid"); + } + + @Test + public void verifyOperationSummaryValidInV2() { + setField("nodes", "paths/get/summary"); + verifyV2("operation-valid"); + } + + @Test + public void verifyOperationSummaryInvalidInV2() { + setField("nodes", "paths/get/summary"); + verifyV2("operation-invalid"); + } + + @Test + public void verifyTagsNameValidInV3() { + setField("nodes", "tags/name"); + verifyV3("tags-valid"); + } + + @Test + public void verifyTagsNameInvalidInV3() { + setField("nodes", "tags/name"); + verifyV3("tags-invalid"); + } + + @Test + public void verifyTagsNameValidInV2() { + setField("nodes", "tags/name"); + verifyV2("tags-valid"); + } + + @Test + public void verifyTagsNameInvalidInV2() { + setField("nodes", "tags/name"); + verifyV2("tags-invalid"); + } + + @Test + public void verifyExternalDocsDescriptionValidInV3() { + setField("nodes", "externalDocs/description"); + verifyV3("external-docs-valid"); + } + + @Test + public void verifyExternalDocsDescriptionInvalidInV3() { + setField("nodes", "externalDocs/description"); + verifyV3("external-docs-invalid"); + } + + @Test + public void verifyExternalDocsDescriptionValidInV2() { + setField("nodes", "externalDocs/description"); + verifyV2("external-docs-valid"); + } + + @Test + public void verifyExternalDocsDescriptionInvalidInV2() { + setField("nodes", "externalDocs/description"); + verifyV2("external-docs-invalid"); + } + + @Test + public void verifyParametersDescriptionValidInV3() { + setField("nodes", "paths/get/parameters/description"); + verifyV3("parameters-valid"); + } + + @Test + public void verifyParametersDescriptionInvalidInV3() { + setField("nodes", "paths/get/parameters/description"); + verifyV3("parameters-invalid"); + } + + @Test + public void verifyBooleanTrueMissingFieldInV3() { + setField("nodes", "info/description"); + setField("valid", "true"); + verifyV3("missing-description"); + + setField("valid", "false"); + verifyV3("info-invalid"); + verifyV3("minimal"); + } + + @Test + public void verifyBooleanTrueMissingFieldInV2() { + setField("nodes", "info/description"); + setField("valid", "true"); + verifyV2("missing-description"); + + setField("valid", "false"); + verifyV2("info-invalid"); + verifyV2("minimal"); + } + + @Test + public void verifyBooleanFalseFieldPresentInV3() { + setField("nodes", "info/description"); + setField("valid", "false"); + verifyV3("info-invalid"); + } + + @Test + public void verifyBooleanFalseFieldPresentInV2() { + setField("nodes", "info/description"); + setField("valid", "false"); + verifyV2("info-invalid"); + } + + @Test + public void verifyBooleanFalseFieldAbsentInV3() { + setField("nodes", "info/description"); + setField("valid", "false"); + verifyV3("minimal"); + } + + @Test + public void verifyBooleanFalseFieldAbsentInV2() { + setField("nodes", "info/description"); + setField("valid", "false"); + verifyV2("minimal"); + } @Override public void verifyRule() { diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/schemas/OAR029StandardResponseSchemaCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/schemas/OAR029StandardResponseSchemaCheckTest.java index f7feae0d..628456db 100644 --- a/src/test/java/apiaddicts/sonar/openapi/checks/schemas/OAR029StandardResponseSchemaCheckTest.java +++ b/src/test/java/apiaddicts/sonar/openapi/checks/schemas/OAR029StandardResponseSchemaCheckTest.java @@ -27,6 +27,21 @@ public void verifyInV2AllOf() { verifyV2("valid-all-of"); } + @Test + public void verifyInV2ValidAllOfMd() { + verifyV2("valid-all-of-md"); + } + + @Test + public void verifyInV2ValidMd() { + verifyV2("valid-md"); + } + + + @Test + public void verifyInV2ValidR() { + verifyV2("valid-r"); + } @Test public void verifyInV3() { @@ -38,6 +53,22 @@ public void verifyInV3AllOf() { verifyV3("valid-all-of"); } + @Test + public void verifyInV3ValidAllOfMd() { + verifyV3("valid-all-of-md"); + } + + @Test + public void verifyInV3ValidMd() { + verifyV3("valid-md"); + } + + @Test + public void verifyInV3ValidR() { + verifyV3("valid-r"); + } + + @Override public void verifyParameters() { assertNumberOfParameters(2); diff --git a/src/test/java/apiaddicts/sonar/openapi/checks/schemas/OAR080SecuritySchemasCheckTest.java b/src/test/java/apiaddicts/sonar/openapi/checks/schemas/OAR080SecuritySchemasCheckTest.java new file mode 100644 index 00000000..1f44678a --- /dev/null +++ b/src/test/java/apiaddicts/sonar/openapi/checks/schemas/OAR080SecuritySchemasCheckTest.java @@ -0,0 +1,95 @@ +package apiaddicts.sonar.openapi.checks.schemas; + +import org.junit.Before; +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 OAR080SecuritySchemasCheckTest extends BaseCheckTest { + + @Before + public void init() { + ruleName = "OAR080"; + check = new OAR080SecuritySchemasCheck(); + v2Path = getV2Path("schemas"); + v3Path = getV3Path("schemas"); + } + + @Test + public void verifyV2WithSecurity() { + verifyV2("with-security"); + } + + @Test + public void verifyV2WithoutSecurity() { + verifyV2("without-security"); + } + + @Test + public void verifyV2GlobalSecurity() { + verifyV2("global-security"); + } + + @Test + public void verifyV2WrongScheme() { + verifyV2("wrong-scheme"); + } + + @Test + public void verifyV2EmptySecurity() { + verifyV2("empty-security"); + } + + @Test + public void verifyV2EmptyGlobalSecurity() { + verifyV2("empty-global-security"); + } + + @Test + public void verifyV3WithSecurity() { + verifyV3("with-security"); + } + + @Test + public void verifyV3WithoutSecurity() { + verifyV3("without-security"); + } + + @Test + public void verifyV3GlobalSecurity() { + verifyV3("global-security"); + } + + @Test + public void verifyV3WrongScheme() { + verifyV3("wrong-scheme"); + } + + @Test + public void verifyV3EmptySecurity() { + verifyV3("empty-security"); + } + + @Test + public void verifyV3EmptyGlobalSecurity() { + verifyV3("empty-global-security"); + } + + @Override + public void verifyRule() { + assertRuleProperties( + "OAR080 - SecuritySchemas - The security scheme must be among those allowed by the organization and must be complete.", + RuleType.VULNERABILITY, + Severity.MAJOR, + tags("schemas") + ); + } + + @Override + public void verifyParameters() { + assertNumberOfParameters(1); + assertParameterProperties("expected-security-scheme", "oauth2, apiKey", RuleParamType.STRING); + } +} diff --git a/src/test/resources/checks/v2/regex/OAR112/external-docs-invalid.json b/src/test/resources/checks/v2/regex/OAR112/external-docs-invalid.json new file mode 100644 index 00000000..5c13a402 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/external-docs-invalid.json @@ -0,0 +1,14 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "externalDocs" : { + "description" : "lowercase external documentation", # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + "url" : "https://example.com" + }, + "paths" : {} +} diff --git a/src/test/resources/checks/v2/regex/OAR112/external-docs-invalid.yaml b/src/test/resources/checks/v2/regex/OAR112/external-docs-invalid.yaml new file mode 100644 index 00000000..fb8623f7 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/external-docs-invalid.yaml @@ -0,0 +1,10 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +externalDocs: + description: lowercase external documentation # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + url: https://example.com +paths: {} diff --git a/src/test/resources/checks/v2/regex/OAR112/external-docs-valid.json b/src/test/resources/checks/v2/regex/OAR112/external-docs-valid.json new file mode 100644 index 00000000..c1b4ce51 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/external-docs-valid.json @@ -0,0 +1,14 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "externalDocs" : { + "description" : "Valid external documentation", + "url" : "https://example.com" + }, + "paths" : {} +} diff --git a/src/test/resources/checks/v2/regex/OAR112/external-docs-valid.yaml b/src/test/resources/checks/v2/regex/OAR112/external-docs-valid.yaml new file mode 100644 index 00000000..6deea6af --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/external-docs-valid.yaml @@ -0,0 +1,10 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +externalDocs: + description: Valid external documentation + url: https://example.com +paths: {} diff --git a/src/test/resources/checks/v2/regex/OAR112/info-invalid.json b/src/test/resources/checks/v2/regex/OAR112/info-invalid.json new file mode 100644 index 00000000..9c1c6937 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/info-invalid.json @@ -0,0 +1,11 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0", + "description" : "lowercase description" # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + }, + "host" : "api.example.com", + "basePath" : "/v1", + "paths" : {} +} diff --git a/src/test/resources/checks/v2/regex/OAR112/info-invalid.yaml b/src/test/resources/checks/v2/regex/OAR112/info-invalid.yaml new file mode 100644 index 00000000..94dc7fff --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/info-invalid.yaml @@ -0,0 +1,8 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 + description: lowercase description # Noncompliant {{OAR112: The field must start with an uppercase letter.}} +host: api.example.com +basePath: /v1 +paths: {} diff --git a/src/test/resources/checks/v2/regex/OAR112/minimal.json b/src/test/resources/checks/v2/regex/OAR112/minimal.json new file mode 100644 index 00000000..c20bf053 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/minimal.json @@ -0,0 +1,10 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "paths" : {} +} diff --git a/src/test/resources/checks/v2/regex/OAR112/minimal.yaml b/src/test/resources/checks/v2/regex/OAR112/minimal.yaml new file mode 100644 index 00000000..a6e9a56d --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/minimal.yaml @@ -0,0 +1,7 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +paths: {} diff --git a/src/test/resources/checks/v2/regex/OAR112/missing-description.json b/src/test/resources/checks/v2/regex/OAR112/missing-description.json new file mode 100644 index 00000000..c6f37935 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/missing-description.json @@ -0,0 +1,10 @@ +{ + "swagger" : "2.0", + "info" : { # Noncompliant {{OAR112: Expected to find a value but didn't.}} + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "paths" : {} +} diff --git a/src/test/resources/checks/v2/regex/OAR112/missing-description.yaml b/src/test/resources/checks/v2/regex/OAR112/missing-description.yaml new file mode 100644 index 00000000..88cf27ff --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/missing-description.yaml @@ -0,0 +1,7 @@ +swagger: '2.0' +info: # Noncompliant {{OAR112: Expected to find a value but didn't.}} + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +paths: {} diff --git a/src/test/resources/checks/v2/regex/OAR112/operation-invalid.json b/src/test/resources/checks/v2/regex/OAR112/operation-invalid.json new file mode 100644 index 00000000..a7747c6a --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/operation-invalid.json @@ -0,0 +1,21 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "paths" : { + "/test" : { + "get" : { + "summary" : "lowercase operation summary", # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + "responses" : { + "200" : { + "description" : "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v2/regex/OAR112/operation-invalid.yaml b/src/test/resources/checks/v2/regex/OAR112/operation-invalid.yaml new file mode 100644 index 00000000..e22dd817 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/operation-invalid.yaml @@ -0,0 +1,13 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +paths: + /test: + get: + summary: lowercase operation summary # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v2/regex/OAR112/operation-valid.json b/src/test/resources/checks/v2/regex/OAR112/operation-valid.json new file mode 100644 index 00000000..1edbf0f0 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/operation-valid.json @@ -0,0 +1,21 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "paths" : { + "/test" : { + "get" : { + "summary" : "Valid Operation Summary", + "responses" : { + "200" : { + "description" : "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v2/regex/OAR112/operation-valid.yaml b/src/test/resources/checks/v2/regex/OAR112/operation-valid.yaml new file mode 100644 index 00000000..a3698a64 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/operation-valid.yaml @@ -0,0 +1,13 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +paths: + /test: + get: + summary: Valid Operation Summary + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v2/regex/OAR112/tags-invalid.json b/src/test/resources/checks/v2/regex/OAR112/tags-invalid.json new file mode 100644 index 00000000..52a0562d --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/tags-invalid.json @@ -0,0 +1,13 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "tags" : [ { + "name" : "invalidTag" # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + } ], + "paths" : {} +} diff --git a/src/test/resources/checks/v2/regex/OAR112/tags-invalid.yaml b/src/test/resources/checks/v2/regex/OAR112/tags-invalid.yaml new file mode 100644 index 00000000..b657bee1 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/tags-invalid.yaml @@ -0,0 +1,9 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +tags: + - name: invalidTag # Noncompliant {{OAR112: The field must start with an uppercase letter.}} +paths: {} diff --git a/src/test/resources/checks/v2/regex/OAR112/tags-valid.json b/src/test/resources/checks/v2/regex/OAR112/tags-valid.json new file mode 100644 index 00000000..91d80136 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/tags-valid.json @@ -0,0 +1,13 @@ +{ + "swagger" : "2.0", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "host" : "api.example.com", + "basePath" : "/v1", + "tags" : [ { + "name" : "ValidTag" + } ], + "paths" : {} +} diff --git a/src/test/resources/checks/v2/regex/OAR112/tags-valid.yaml b/src/test/resources/checks/v2/regex/OAR112/tags-valid.yaml new file mode 100644 index 00000000..0bad0c33 --- /dev/null +++ b/src/test/resources/checks/v2/regex/OAR112/tags-valid.yaml @@ -0,0 +1,9 @@ +swagger: '2.0' +info: + title: Test API + version: 1.0.0 +host: api.example.com +basePath: /v1 +tags: + - name: ValidTag +paths: {} diff --git a/src/test/resources/checks/v2/schemas/OAR080/.gitkeep b/src/test/resources/checks/v2/schemas/OAR080/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/test/resources/checks/v2/schemas/OAR080/empty-global-security.json b/src/test/resources/checks/v2/schemas/OAR080/empty-global-security.json new file mode 100644 index 00000000..cf2c9091 --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/empty-global-security.json @@ -0,0 +1,27 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "security": [], + "securityDefinitions": { + "apiKey": { + "type": "apiKey", + "name": "X-API-Key", + "in": "header" + } + }, + "paths": { + "/users": { + "get": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Get all users", + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v2/schemas/OAR080/empty-global-security.yaml b/src/test/resources/checks/v2/schemas/OAR080/empty-global-security.yaml new file mode 100644 index 00000000..1711e583 --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/empty-global-security.yaml @@ -0,0 +1,17 @@ +swagger: "2.0" +info: + version: "1.0.0" + title: "Sample API" +security: [] +securityDefinitions: + apiKey: + type: apiKey + name: X-API-Key + in: header +paths: + /users: + get: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Get all users + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v2/schemas/OAR080/empty-security.json b/src/test/resources/checks/v2/schemas/OAR080/empty-security.json new file mode 100644 index 00000000..ace8b8b4 --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/empty-security.json @@ -0,0 +1,38 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "securityDefinitions": { + "apiKey": { + "type": "apiKey", + "name": "X-API-Key", + "in": "header" + } + }, + "paths": { + "/users": { + "get": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Get all users", + "security": [], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/products": { + "post": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Create a new product", + "security": [], + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v2/schemas/OAR080/empty-security.yaml b/src/test/resources/checks/v2/schemas/OAR080/empty-security.yaml new file mode 100644 index 00000000..389de1e9 --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/empty-security.yaml @@ -0,0 +1,24 @@ +swagger: "2.0" +info: + version: "1.0.0" + title: "Sample API" +securityDefinitions: + apiKey: + type: apiKey + name: X-API-Key + in: header +paths: + /users: + get: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Get all users + security: [] + responses: + '200': + description: OK + /products: + post: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Create a new product + security: [] + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v2/schemas/OAR080/global-security.json b/src/test/resources/checks/v2/schemas/OAR080/global-security.json new file mode 100644 index 00000000..4b6dd680 --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/global-security.json @@ -0,0 +1,48 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "security": [ + { "apiKey": [] }, + { "oauth2": [] } + ], + "securityDefinitions": { + "oauth2": { + "type": "oauth2", + "flow": "implicit", + "authorizationUrl": "https://example.com/oauth/authorize", + "scopes": { + "read": "Read access" + } + }, + "apiKey": { + "type": "apiKey", + "name": "X-API-Key", + "in": "header" + } + }, + "paths": { + "/users": { + "get": { + "summary": "Get all users", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/products": { + "post": { + "summary": "Create a new product", + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v2/schemas/OAR080/global-security.yaml b/src/test/resources/checks/v2/schemas/OAR080/global-security.yaml new file mode 100644 index 00000000..4fa12698 --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/global-security.yaml @@ -0,0 +1,49 @@ +swagger: "2.0" +info: + version: "1.0.0" + title: "Sample API" +security: + - apiKey: [] + - oauth2: [] +securityDefinitions: + oauth2: + type: oauth2 + flow: implicit + authorizationUrl: https://example.com/oauth/authorize + scopes: + read: Read access + apiKey: + type: apiKey + name: X-API-Key + in: header +paths: + /users: + get: + summary: Get all users + responses: + '200': + description: OK + /products: + post: + summary: Create a new product + responses: + '200': + description: OK + /orders: + put: + summary: Update an order + responses: + '200': + description: OK + /invoices: + delete: + summary: Delete an invoice + responses: + '200': + description: OK + /items: + patch: + summary: Patch an item + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v2/schemas/OAR080/wrong-scheme.json b/src/test/resources/checks/v2/schemas/OAR080/wrong-scheme.json new file mode 100644 index 00000000..f15da5bb --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/wrong-scheme.json @@ -0,0 +1,61 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "securityDefinitions": { + "unknownScheme": { + "type": "apiKey", + "name": "X-Token", + "in": "header" + } + }, + "paths": { + "/users": { + "get": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Get all users", + "security": [ + { + "unknownScheme": [] + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/products": { + "post": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Create a new product", + "security": [ + { + "apiKey": [] + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/orders": { + "patch": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Patch an order", + "security": [ + { + "unknownScheme": [] + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v2/schemas/OAR080/wrong-scheme.yaml b/src/test/resources/checks/v2/schemas/OAR080/wrong-scheme.yaml new file mode 100644 index 00000000..14e347a0 --- /dev/null +++ b/src/test/resources/checks/v2/schemas/OAR080/wrong-scheme.yaml @@ -0,0 +1,40 @@ +swagger: "2.0" +info: + version: "1.0.0" + title: "Sample API" +securityDefinitions: + unknownScheme: + type: apiKey + name: X-Token + in: header +paths: + /users: + get: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Get all users + security: + - unknownScheme: [] + responses: + '200': + description: OK + /products: + post: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Create a new product + security: + - apiKey: [] + responses: + '200': + description: OK + /orders: + patch: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Patch an order + security: + - unknownScheme: [] + responses: + '200': + description: OK + /items: + head: + summary: Head items (non-security verb, no issue) + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/regex/OAR112/external-docs-invalid.json b/src/test/resources/checks/v3/regex/OAR112/external-docs-invalid.json new file mode 100644 index 00000000..17586e7f --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/external-docs-invalid.json @@ -0,0 +1,12 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "externalDocs" : { + "description" : "lowercase external documentation", # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + "url" : "https://example.com" + }, + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/external-docs-invalid.yaml b/src/test/resources/checks/v3/regex/OAR112/external-docs-invalid.yaml new file mode 100644 index 00000000..587823ce --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/external-docs-invalid.yaml @@ -0,0 +1,8 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +externalDocs: + description: lowercase external documentation # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + url: https://example.com +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/external-docs-valid.json b/src/test/resources/checks/v3/regex/OAR112/external-docs-valid.json new file mode 100644 index 00000000..b557673e --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/external-docs-valid.json @@ -0,0 +1,12 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "externalDocs" : { + "description" : "Valid external documentation", + "url" : "https://example.com" + }, + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/external-docs-valid.yaml b/src/test/resources/checks/v3/regex/OAR112/external-docs-valid.yaml new file mode 100644 index 00000000..a273f219 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/external-docs-valid.yaml @@ -0,0 +1,8 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +externalDocs: + description: Valid external documentation + url: https://example.com +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/info-invalid.json b/src/test/resources/checks/v3/regex/OAR112/info-invalid.json new file mode 100644 index 00000000..1febb6b1 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/info-invalid.json @@ -0,0 +1,9 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0", + "description" : "lowercase description" # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + }, + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/info-invalid.yaml b/src/test/resources/checks/v3/regex/OAR112/info-invalid.yaml new file mode 100644 index 00000000..32fbcf71 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/info-invalid.yaml @@ -0,0 +1,6 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 + description: lowercase description # Noncompliant {{OAR112: The field must start with an uppercase letter.}} +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/minimal.json b/src/test/resources/checks/v3/regex/OAR112/minimal.json new file mode 100644 index 00000000..2c084747 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/minimal.json @@ -0,0 +1,8 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/minimal.yaml b/src/test/resources/checks/v3/regex/OAR112/minimal.yaml new file mode 100644 index 00000000..f379c272 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/minimal.yaml @@ -0,0 +1,5 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/missing-description.json b/src/test/resources/checks/v3/regex/OAR112/missing-description.json new file mode 100644 index 00000000..f2549007 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/missing-description.json @@ -0,0 +1,8 @@ +{ + "openapi" : "3.0.3", + "info" : { # Noncompliant {{OAR112: Expected to find a value but didn't.}} + "title" : "Test API", + "version" : "1.0.0" + }, + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/missing-description.yaml b/src/test/resources/checks/v3/regex/OAR112/missing-description.yaml new file mode 100644 index 00000000..db4ae777 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/missing-description.yaml @@ -0,0 +1,5 @@ +openapi: 3.0.3 +info: # Noncompliant {{OAR112: Expected to find a value but didn't.}} + title: Test API + version: 1.0.0 +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/operation-invalid.json b/src/test/resources/checks/v3/regex/OAR112/operation-invalid.json new file mode 100644 index 00000000..8bfbed2b --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/operation-invalid.json @@ -0,0 +1,19 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "paths" : { + "/test" : { + "get" : { + "summary" : "lowercase operation summary", # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + "responses" : { + "200" : { + "description" : "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/regex/OAR112/operation-invalid.yaml b/src/test/resources/checks/v3/regex/OAR112/operation-invalid.yaml new file mode 100644 index 00000000..0bc1243b --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/operation-invalid.yaml @@ -0,0 +1,11 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +paths: + /test: + get: + summary: lowercase operation summary # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/regex/OAR112/operation-valid.json b/src/test/resources/checks/v3/regex/OAR112/operation-valid.json new file mode 100644 index 00000000..84ad7faa --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/operation-valid.json @@ -0,0 +1,19 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "paths" : { + "/test" : { + "get" : { + "summary" : "Valid Operation Summary", + "responses" : { + "200" : { + "description" : "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/regex/OAR112/operation-valid.yaml b/src/test/resources/checks/v3/regex/OAR112/operation-valid.yaml new file mode 100644 index 00000000..9b62b40c --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/operation-valid.yaml @@ -0,0 +1,11 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +paths: + /test: + get: + summary: Valid Operation Summary + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/regex/OAR112/parameters-invalid.json b/src/test/resources/checks/v3/regex/OAR112/parameters-invalid.json new file mode 100644 index 00000000..46495733 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/parameters-invalid.json @@ -0,0 +1,26 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "paths" : { + "/test" : { + "get" : { + "parameters" : [ { + "name" : "page", + "in" : "query", + "description" : "lowercase parameter description", # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + "schema" : { + "type" : "integer" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/regex/OAR112/parameters-invalid.yaml b/src/test/resources/checks/v3/regex/OAR112/parameters-invalid.yaml new file mode 100644 index 00000000..86159506 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/parameters-invalid.yaml @@ -0,0 +1,16 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +paths: + /test: + get: + parameters: + - name: page + in: query + description: lowercase parameter description # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + schema: + type: integer + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/regex/OAR112/parameters-valid.json b/src/test/resources/checks/v3/regex/OAR112/parameters-valid.json new file mode 100644 index 00000000..27af1750 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/parameters-valid.json @@ -0,0 +1,26 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "paths" : { + "/test" : { + "get" : { + "parameters" : [ { + "name" : "page", + "in" : "query", + "description" : "Valid parameter description", + "schema" : { + "type" : "integer" + } + } ], + "responses" : { + "200" : { + "description" : "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/regex/OAR112/parameters-valid.yaml b/src/test/resources/checks/v3/regex/OAR112/parameters-valid.yaml new file mode 100644 index 00000000..9ec6ebd6 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/parameters-valid.yaml @@ -0,0 +1,16 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +paths: + /test: + get: + parameters: + - name: page + in: query + description: Valid parameter description + schema: + type: integer + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/regex/OAR112/servers-invalid.json b/src/test/resources/checks/v3/regex/OAR112/servers-invalid.json new file mode 100644 index 00000000..c5cda036 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/servers-invalid.json @@ -0,0 +1,12 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "servers" : [ { + "url" : "https://api.example.com", + "description" : "lowercase server description" # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + } ], + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/servers-invalid.yaml b/src/test/resources/checks/v3/regex/OAR112/servers-invalid.yaml new file mode 100644 index 00000000..835f2b06 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/servers-invalid.yaml @@ -0,0 +1,8 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +servers: + - url: https://api.example.com + description: lowercase server description # Noncompliant {{OAR112: The field must start with an uppercase letter.}} +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/servers-valid.json b/src/test/resources/checks/v3/regex/OAR112/servers-valid.json new file mode 100644 index 00000000..735983f4 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/servers-valid.json @@ -0,0 +1,12 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "servers" : [ { + "url" : "https://api.example.com", + "description" : "Valid server description" + } ], + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/servers-valid.yaml b/src/test/resources/checks/v3/regex/OAR112/servers-valid.yaml new file mode 100644 index 00000000..511f93d7 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/servers-valid.yaml @@ -0,0 +1,8 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +servers: + - url: https://api.example.com + description: Valid server description +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/tags-invalid.json b/src/test/resources/checks/v3/regex/OAR112/tags-invalid.json new file mode 100644 index 00000000..5995f7ba --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/tags-invalid.json @@ -0,0 +1,11 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "tags" : [ { + "name" : "invalidTag" # Noncompliant {{OAR112: The field must start with an uppercase letter.}} + } ], + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/tags-invalid.yaml b/src/test/resources/checks/v3/regex/OAR112/tags-invalid.yaml new file mode 100644 index 00000000..48c06b71 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/tags-invalid.yaml @@ -0,0 +1,7 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +tags: + - name: invalidTag # Noncompliant {{OAR112: The field must start with an uppercase letter.}} +paths: {} diff --git a/src/test/resources/checks/v3/regex/OAR112/tags-valid.json b/src/test/resources/checks/v3/regex/OAR112/tags-valid.json new file mode 100644 index 00000000..f28ad145 --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/tags-valid.json @@ -0,0 +1,11 @@ +{ + "openapi" : "3.0.3", + "info" : { + "title" : "Test API", + "version" : "1.0.0" + }, + "tags" : [ { + "name" : "ValidTag" + } ], + "paths" : {} +} diff --git a/src/test/resources/checks/v3/regex/OAR112/tags-valid.yaml b/src/test/resources/checks/v3/regex/OAR112/tags-valid.yaml new file mode 100644 index 00000000..045b483f --- /dev/null +++ b/src/test/resources/checks/v3/regex/OAR112/tags-valid.yaml @@ -0,0 +1,7 @@ +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +tags: + - name: ValidTag +paths: {} diff --git a/src/test/resources/checks/v3/schemas/OAR080/.gitkeep b/src/test/resources/checks/v3/schemas/OAR080/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/test/resources/checks/v3/schemas/OAR080/empty-global-security.json b/src/test/resources/checks/v3/schemas/OAR080/empty-global-security.json new file mode 100644 index 00000000..81763b5c --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/empty-global-security.json @@ -0,0 +1,20 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "security": [], + "paths": { + "/users": { + "get": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Get all users", + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/schemas/OAR080/empty-global-security.yaml b/src/test/resources/checks/v3/schemas/OAR080/empty-global-security.yaml new file mode 100644 index 00000000..05fb3ba3 --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/empty-global-security.yaml @@ -0,0 +1,12 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Sample API +security: [] +paths: + /users: + get: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Get all users + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/schemas/OAR080/empty-security.json b/src/test/resources/checks/v3/schemas/OAR080/empty-security.json new file mode 100644 index 00000000..b7f31ef0 --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/empty-security.json @@ -0,0 +1,31 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "paths": { + "/users": { + "get": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Get all users", + "security": [], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/products": { + "post": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Create a new product", + "security": [], + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/schemas/OAR080/empty-security.yaml b/src/test/resources/checks/v3/schemas/OAR080/empty-security.yaml new file mode 100644 index 00000000..8821cacf --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/empty-security.yaml @@ -0,0 +1,19 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Sample API +paths: + /users: + get: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Get all users + security: [] + responses: + '200': + description: OK + /products: + post: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Create a new product + security: [] + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/schemas/OAR080/global-security.json b/src/test/resources/checks/v3/schemas/OAR080/global-security.json new file mode 100644 index 00000000..645a4a88 --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/global-security.json @@ -0,0 +1,53 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "security": [ + { "apiKey": [] }, + { "oauth2": [] } + ], + "components": { + "securitySchemes": { + "oauth2": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://example.com/oauth/authorize", + "scopes": { + "read": "Read access" + } + } + } + }, + "apiKey": { + "type": "apiKey", + "name": "X-API-Key", + "in": "header" + } + } + }, + "paths": { + "/users": { + "get": { + "summary": "Get all users", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/products": { + "post": { + "summary": "Create a new product", + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/schemas/OAR080/global-security.yaml b/src/test/resources/checks/v3/schemas/OAR080/global-security.yaml new file mode 100644 index 00000000..3205ed2a --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/global-security.yaml @@ -0,0 +1,51 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Sample API +security: + - apiKey: [] + - oauth2: [] +components: + securitySchemes: + oauth2: + type: oauth2 + flows: + implicit: + authorizationUrl: https://example.com/oauth/authorize + scopes: + read: Read access + apiKey: + type: apiKey + name: X-API-Key + in: header +paths: + /users: + get: + summary: Get all users + responses: + '200': + description: OK + /products: + post: + summary: Create a new product + responses: + '200': + description: OK + /orders: + put: + summary: Update an order + responses: + '200': + description: OK + /invoices: + delete: + summary: Delete an invoice + responses: + '200': + description: OK + /items: + patch: + summary: Patch an item + responses: + '200': + description: OK diff --git a/src/test/resources/checks/v3/schemas/OAR080/wrong-scheme.json b/src/test/resources/checks/v3/schemas/OAR080/wrong-scheme.json new file mode 100644 index 00000000..b042b2b4 --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/wrong-scheme.json @@ -0,0 +1,54 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Sample API" + }, + "paths": { + "/users": { + "get": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Get all users", + "security": [ + { + "unknownScheme": [] + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/products": { + "post": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Create a new product", + "security": [ + { + "apiKey": [] + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/orders": { + "patch": { # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + "summary": "Patch an order", + "security": [ + { + "unknownScheme": [] + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + } +} diff --git a/src/test/resources/checks/v3/schemas/OAR080/wrong-scheme.yaml b/src/test/resources/checks/v3/schemas/OAR080/wrong-scheme.yaml new file mode 100644 index 00000000..86220d9f --- /dev/null +++ b/src/test/resources/checks/v3/schemas/OAR080/wrong-scheme.yaml @@ -0,0 +1,35 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Sample API +paths: + /users: + get: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Get all users + security: + - unknownScheme: [] + responses: + '200': + description: OK + /products: + post: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Create a new product + security: + - apiKey: [] + responses: + '200': + description: OK + /orders: + patch: # Noncompliant {{OAR080: The security scheme must be among those allowed by the organization and must be complete.}} + summary: Patch an order + security: + - unknownScheme: [] + responses: + '200': + description: OK + /items: + head: + summary: Head – non-security verb, ignored + responses: + '200': + description: OK