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   [](https://www.gnu.org/licenses/lgpl-3.0)
+# 🛠️ sonaropenapi-rules   [](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