From 74f4090c01b7a1e56bb442d567c8a0c9d7e22aa1 Mon Sep 17 00:00:00 2001 From: Melsy Huamani Date: Tue, 18 Aug 2026 13:49:47 -0500 Subject: [PATCH 1/7] feat: accept OpenAPI 3.0.4, 3.1.1 and 3.1.2 in dispatch and grammars --- CHANGELOG.md | 6 +++ README.md | 2 +- its/pom.xml | 2 +- openapi-checks/pom.xml | 2 +- openapi-front-end/pom.xml | 2 +- .../dosonarapi/api/v3/OpenApi3Grammar.java | 2 +- .../dosonarapi/api/v31/OpenApi31Grammar.java | 29 ++++++++++-- .../dosonarapi/api/v32/OpenApi32Grammar.java | 2 + .../dosonarapi/api/v31/JsonSchemaTest.java | 21 +++++++++ .../openapi/parser/OpenApiParserTest.java | 33 +++++++++++++ .../models/v31/jsonschemakeywords.yaml | 46 +++++++++++++++++++ .../resources/models/v31/webhooksonly.yaml | 18 ++++++++ openapi-test-tools/pom.xml | 2 +- pom.xml | 2 +- sonar-openapi-plugin/pom.xml | 2 +- .../dosonarapi/plugin/OpenApiAnalyzer.java | 10 +++- 16 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 openapi-front-end/src/test/resources/models/v31/jsonschemakeywords.yaml create mode 100644 openapi-front-end/src/test/resources/models/v31/webhooksonly.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index d97cfab..4aa9ea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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.2.2-beta-1] - 2026-08-18 + +### Added + +- Accept OpenAPI `3.0.4`, `3.1.1` and `3.1.2` in version dispatch and the v3/v3.1/v3.2 grammars. + ## [1.2.1] - 2026-06-04 ### Added diff --git a/README.md b/README.md index 852982a..8a5cd0e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Feel free to drop by and greet us on our GitHub discussion or Discord chat. You ## ⚙️ Features -* Full compatibility with OpenAPI v2.0, v3.0.0, v3.0.1, v3.0.2, v3.0.3, v3.1.0 and v3.2.0 +* Full compatibility with OpenAPI v2.0, v3.0.0, v3.0.1, v3.0.2, v3.0.3, v3.0.4, v3.1.0, v3.1.1, v3.1.2 and v3.2.0 ![SonarOpenApi in action](sonarqube.jpg) diff --git a/its/pom.xml b/its/pom.xml index 49f6740..37277d6 100644 --- a/its/pom.xml +++ b/its/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.1 + 1.2.2-beta-1 ../pom.xml 4.0.0 diff --git a/openapi-checks/pom.xml b/openapi-checks/pom.xml index 4ae3c61..ae89cbb 100644 --- a/openapi-checks/pom.xml +++ b/openapi-checks/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.1 + 1.2.2-beta-1 ../pom.xml diff --git a/openapi-front-end/pom.xml b/openapi-front-end/pom.xml index 9c28b76..1d6729c 100644 --- a/openapi-front-end/pom.xml +++ b/openapi-front-end/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.1 + 1.2.2-beta-1 ../pom.xml diff --git a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java index d275bc8..38156ed 100644 --- a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java +++ b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java @@ -83,7 +83,7 @@ public static YamlGrammarBuilder create() { b.setRootRule(ROOT); b.rule(ROOT).is(b.object( - b.mandatoryProperty("openapi", b.firstOf("3.0.0", "3.0.1", "3.0.2", "3.0.3")), + b.mandatoryProperty("openapi", b.firstOf("3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4")), b.mandatoryProperty("info", INFO), b.property("servers", b.array(SERVER)), b.mandatoryProperty("paths", PATHS), diff --git a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java index b359e92..74c01ef 100644 --- a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java +++ b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java @@ -78,6 +78,7 @@ public enum OpenApi31Grammar implements GrammarRuleKey { SECURITY_SCHEMES, LINKS_COMPONENT, CALLBACKS_COMPONENT, + PATH_ITEMS_COMPONENT, SCHEMA_PROPERTIES, DESCRIPTION; @@ -88,10 +89,11 @@ public static YamlGrammarBuilder create() { b.setRootRule(ROOT); b.rule(ROOT).is(b.object( - b.mandatoryProperty("openapi", "3.1.0"), + b.mandatoryProperty("openapi", b.firstOf("3.1.0", "3.1.1", "3.1.2")), b.mandatoryProperty("info", INFO), + b.property("jsonSchemaDialect", b.string()), b.property("servers", b.array(SERVER)), - b.mandatoryProperty("paths", PATHS), + b.property("paths", PATHS), b.property("webhooks", WEBHOOKS), b.property("components", COMPONENTS), b.property("security", b.array(SECURITY_REQUIREMENT)), @@ -151,12 +153,14 @@ private static void buildComponents(YamlGrammarBuilder b) { b.property("securitySchemes", SECURITY_SCHEMES), b.property("links", LINKS_COMPONENT), b.property("callbacks", CALLBACKS_COMPONENT), + b.property("pathItems", PATH_ITEMS_COMPONENT), b.patternProperty(EXTENSION_PATTERN, b.anything()))); OpenApiGrammar.buildBaseComponentRules(b, SCHEMAS_COMPONENT, RESPONSES_COMPONENT, PARAMETERS_COMPONENT, EXAMPLES_COMPONENT, BODIES_COMPONENT, HEADERS_COMPONENT, SECURITY_SCHEMES, LINKS_COMPONENT, CALLBACKS_COMPONENT, REF, SCHEMA, RESPONSE, PARAMETER, EXAMPLE, REQUEST_BODY, HEADER, SECURITY_SCHEME, LINK, CALLBACK); b.rule(WEBHOOKS_COMPONENT).is(b.object(b.patternProperty(".*", b.firstOf(REF, WEBHOOK)))); + b.rule(PATH_ITEMS_COMPONENT).is(b.object(b.patternProperty(".*", b.firstOf(REF, PATH)))); buildParameters(b); buildResponses(b); @@ -185,16 +189,35 @@ private static void buildSchema(YamlGrammarBuilder b) { b.property("type", b.firstOf(b.string(), b.array(b.string()))), b.property("contentMediaType", b.string()), b.property("contentEncoding", b.string()), + b.property("contentSchema", b.firstOf(REF, SCHEMA)), b.property("allOf", b.array(b.firstOf(REF, SCHEMA))), b.property("oneOf", b.array(b.firstOf(REF, SCHEMA))), b.property("anyOf", b.array(b.firstOf(REF, SCHEMA))), b.property("not", b.firstOf(REF, SCHEMA)), + b.property("if", b.firstOf(REF, SCHEMA)), + b.property("then", b.firstOf(REF, SCHEMA)), + b.property("else", b.firstOf(REF, SCHEMA)), + b.property("prefixItems", b.array(b.firstOf(REF, SCHEMA))), b.property("items", b.firstOf(REF, SCHEMA)), + b.property("contains", b.firstOf(REF, SCHEMA)), + b.property("minContains", b.integer()), + b.property("maxContains", b.integer()), + b.property("unevaluatedItems", b.firstOf(b.bool(), REF, SCHEMA)), b.property("properties", SCHEMA_PROPERTIES), + b.property("patternProperties", SCHEMA_PROPERTIES), + b.property("propertyNames", b.firstOf(REF, SCHEMA)), + b.property("dependentSchemas", b.object(b.patternProperty(".*", b.firstOf(REF, SCHEMA)))), + b.property("dependentRequired", b.object(b.patternProperty(".*", b.array(b.string())))), b.property("$schema", b.string()), + b.property("$id", b.string()), + b.property("$anchor", b.string()), + b.property("$defs", b.object(b.patternProperty(".*", b.firstOf(REF, SCHEMA)))), + b.property("$dynamicRef", b.string()), + b.property("$dynamicAnchor", b.string()), + b.property("$comment", b.string()), b.property("additionalProperties", b.firstOf(b.bool(), REF, SCHEMA)), b.property("description", DESCRIPTION), - b.property("unevaluatedProperties", b.bool()), + b.property("unevaluatedProperties", b.firstOf(b.bool(), REF, SCHEMA)), b.property("format", b.string()), b.property("default", b.anything()), b.property("nullable", b.bool()), diff --git a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java index 7a6827c..3fb0e9e 100644 --- a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java +++ b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java @@ -236,6 +236,7 @@ private static void buildSchema(YamlGrammarBuilder b) { b.property("type", b.firstOf(b.string(), b.array(b.string()))), b.property("contentMediaType", b.string()), b.property("contentEncoding", b.string()), + b.property("contentSchema", b.firstOf(REF, SCHEMA)), b.property("allOf", b.array(b.firstOf(REF, SCHEMA))), b.property("oneOf", b.array(b.firstOf(REF, SCHEMA))), b.property("anyOf", b.array(b.firstOf(REF, SCHEMA))), @@ -255,6 +256,7 @@ private static void buildSchema(YamlGrammarBuilder b) { b.property("dependentSchemas", b.object(b.patternProperty(".*", b.firstOf(REF, SCHEMA)))), b.property("dependentRequired", b.object(b.patternProperty(".*", b.array(b.string())))), b.property("$schema", b.string()), + b.property("$id", b.string()), b.property("$anchor", b.string()), b.property("$defs", b.object(b.patternProperty(".*", b.firstOf(REF, SCHEMA)))), b.property("$dynamicRef", b.string()), diff --git a/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/api/v31/JsonSchemaTest.java b/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/api/v31/JsonSchemaTest.java index 61a7c6f..cb5a288 100644 --- a/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/api/v31/JsonSchemaTest.java +++ b/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/api/v31/JsonSchemaTest.java @@ -23,6 +23,8 @@ import org.junit.Test; import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode; +import static org.assertj.core.api.Assertions.assertThat; + public class JsonSchemaTest extends BaseNodeTest { @Test @@ -48,4 +50,23 @@ public class JsonSchemaTest extends BaseNodeTest { JsonNode param = node.at("/value"); assertEquals("http://json-schema.org/draft-07/schema#", param, "/$schema"); } + + @Test + public void json_schema_keywords() { + JsonNode node = parseResource(OpenApi31Grammar.SCHEMA, "/models/v31/jsonschemakeywords.yaml"); + + assertThat(issues).isEmpty(); + assertEquals("https://example.com/schemas/person", node, "/$id"); + assertEquals("base64", node, "/properties/id/contentEncoding"); + assertEquals("1", node, "/properties/tags/minContains"); + } + + @Test + public void root_without_paths_with_dialect_and_path_items() { + JsonNode node = parseResource(OpenApi31Grammar.ROOT, "/models/v31/webhooksonly.yaml"); + + assertThat(issues).isEmpty(); + assertEquals("https://spec.openapis.org/oas/3.1/dialect/base", node, "/jsonSchemaDialect"); + assertMissing(node.at("/paths")); + } } diff --git a/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/openapi/parser/OpenApiParserTest.java b/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/openapi/parser/OpenApiParserTest.java index 643f3b3..b2d90a4 100644 --- a/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/openapi/parser/OpenApiParserTest.java +++ b/openapi-front-end/src/test/java/org/apiaddicts/apitools/dosonarapi/openapi/parser/OpenApiParserTest.java @@ -30,6 +30,7 @@ public class OpenApiParserTest { private static final OpenApiConfiguration CONFIG = new OpenApiConfiguration(StandardCharsets.UTF_8, false); + private static final OpenApiConfiguration STRICT = new OpenApiConfiguration(StandardCharsets.UTF_8, true); private static final String MINIMAL_V2 = "swagger: \"2.0\"\n" + @@ -45,6 +46,14 @@ public class OpenApiParserTest { " version: 1.0.0\n" + "paths: {}"; + private static String minimalOpenApi(String version) { + return "openapi: \"" + version + "\"\n" + + "info:\n" + + " title: Test\n" + + " version: 1.0.0\n" + + "paths: {}"; + } + @Test public void create_v2_parser_parses_swagger_doc() { YamlParser parser = OpenApiParser.createV2(CONFIG); @@ -63,6 +72,30 @@ public void create_v3_parser_parses_openapi_doc() { assertThat(root.at("/openapi").getTokenValue()).isEqualTo("3.0.0"); } + @Test + public void create_v3_parser_accepts_openapi_304() { + YamlParser parser = OpenApiParser.createV3(STRICT); + JsonNode root = parser.parse(minimalOpenApi("3.0.4")); + assertThat(root).isNotNull(); + assertThat(root.at("/openapi").getTokenValue()).isEqualTo("3.0.4"); + } + + @Test + public void create_v31_parser_accepts_openapi_311() { + YamlParser parser = OpenApiParser.createV31(STRICT); + JsonNode root = parser.parse(minimalOpenApi("3.1.1")); + assertThat(root).isNotNull(); + assertThat(root.at("/openapi").getTokenValue()).isEqualTo("3.1.1"); + } + + @Test + public void create_v31_parser_accepts_openapi_312() { + YamlParser parser = OpenApiParser.createV31(STRICT); + JsonNode root = parser.parse(minimalOpenApi("3.1.2")); + assertThat(root).isNotNull(); + assertThat(root.at("/openapi").getTokenValue()).isEqualTo("3.1.2"); + } + @Test public void create_v31_parser_returns_non_null() { YamlParser parser = OpenApiParser.createV31(CONFIG); diff --git a/openapi-front-end/src/test/resources/models/v31/jsonschemakeywords.yaml b/openapi-front-end/src/test/resources/models/v31/jsonschemakeywords.yaml new file mode 100644 index 0000000..fc2f7e0 --- /dev/null +++ b/openapi-front-end/src/test/resources/models/v31/jsonschemakeywords.yaml @@ -0,0 +1,46 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "https://example.com/schemas/person" +$anchor: "person" +$comment: "Exercises JSON Schema keywords supported by OpenAPI 3.1" +$defs: + name: + type: string +type: [object, "null"] +properties: + id: + type: [string, "null"] + contentEncoding: base64 + contentMediaType: application/json + contentSchema: + type: object + tags: + type: array + prefixItems: + - type: string + - type: integer + items: + type: string + contains: + type: string + minContains: 1 + maxContains: 5 + unevaluatedItems: false +patternProperties: + "^x-meta-": + type: string +propertyNames: + pattern: "^[a-z]+$" +dependentSchemas: + creditCard: + required: [billingAddress] +dependentRequired: + creditCard: [billingAddress] +if: + properties: + kind: + const: admin +then: + required: [permissions] +else: + required: [role] +unevaluatedProperties: false diff --git a/openapi-front-end/src/test/resources/models/v31/webhooksonly.yaml b/openapi-front-end/src/test/resources/models/v31/webhooksonly.yaml new file mode 100644 index 0000000..b984db4 --- /dev/null +++ b/openapi-front-end/src/test/resources/models/v31/webhooksonly.yaml @@ -0,0 +1,18 @@ +openapi: "3.1.1" +info: + title: Webhooks only + version: 1.0.0 +jsonSchemaDialect: "https://spec.openapis.org/oas/3.1/dialect/base" +webhooks: + newPet: + post: + responses: + '200': + description: ok +components: + pathItems: + petItem: + get: + responses: + '200': + description: ok diff --git a/openapi-test-tools/pom.xml b/openapi-test-tools/pom.xml index cf684f6..8ed2d72 100644 --- a/openapi-test-tools/pom.xml +++ b/openapi-test-tools/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.1 + 1.2.2-beta-1 ../pom.xml diff --git a/pom.xml b/pom.xml index 5719259..c47f9ce 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.1 + 1.2.2-beta-1 pom SonarOpenAPI diff --git a/sonar-openapi-plugin/pom.xml b/sonar-openapi-plugin/pom.xml index 957db01..e365ba6 100644 --- a/sonar-openapi-plugin/pom.xml +++ b/sonar-openapi-plugin/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.1 + 1.2.2-beta-1 ../pom.xml diff --git a/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java b/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java index 8ed5257..5f4fe9d 100644 --- a/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java +++ b/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java @@ -112,7 +112,13 @@ public void scanFiles() { private static boolean isV3Version(JsonNode openapiNode) { if (openapiNode.isMissing()) return false; String v = openapiNode.getTokenValue(); - return "3.0.0".equals(v) || "3.0.1".equals(v) || "3.0.2".equals(v) || "3.0.3".equals(v); + return "3.0.0".equals(v) || "3.0.1".equals(v) || "3.0.2".equals(v) || "3.0.3".equals(v) || "3.0.4".equals(v); + } + + private static boolean isV31Version(JsonNode openapiNode) { + if (openapiNode.isMissing()) return false; + String v = openapiNode.getTokenValue(); + return "3.1.0".equals(v) || "3.1.1".equals(v) || "3.1.2".equals(v); } private YamlParser selectParser(boolean isV2, boolean isV3, boolean isV31, boolean isV32) { @@ -133,7 +139,7 @@ private void scanFile(InputFile inputFile) { boolean isV2 = !rootNode.at("/swagger").isMissing(); JsonNode openapiNode = rootNode.at("/openapi"); boolean isV3 = isV3Version(openapiNode); - boolean isV31 = !openapiNode.isMissing() && openapiNode.getTokenValue().equals("3.1.0"); + boolean isV31 = isV31Version(openapiNode); boolean isV32 = !openapiNode.isMissing() && openapiNode.getTokenValue().equals("3.2.0"); YamlParser targetParser = selectParser(isV2, isV3, isV31, isV32); if (targetParser == null) return; From ad3d17f24fadef65f13752f33bf5202d14ad012a Mon Sep 17 00:00:00 2001 From: Melsy Huamani Date: Wed, 19 Aug 2026 09:34:33 -0500 Subject: [PATCH 2/7] fix: run Sonar scanner on JDK 21 with pinned plugin coordinates --- .github/workflows/maven.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index efe3046..57b0cab 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -23,10 +23,16 @@ jobs: cache: maven - name: Build, Test and Coverage run: mvn -B verify --file pom.xml + - name: Set up JDK 21 for Sonar + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven - name: SonarCloud Analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn sonar:sonar -Dsonar.token=$SONAR_TOKEN + run: mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.11.0.3922:sonar -Dsonar.token=$SONAR_TOKEN - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@v4 From f5b498518ae16adc4a72a4a955ac5f0f7857a749 Mon Sep 17 00:00:00 2001 From: Melsy Huamani Date: Tue, 25 Aug 2026 13:19:59 -0500 Subject: [PATCH 3/7] update version and changelog --- CHANGELOG.md | 2 +- its/pom.xml | 2 +- openapi-checks/pom.xml | 2 +- openapi-front-end/pom.xml | 2 +- openapi-test-tools/pom.xml | 2 +- pom.xml | 2 +- sonar-openapi-plugin/pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aa9ea5..e3dab72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ 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.2.2-beta-1] - 2026-08-18 +## [1.3.0-beta-1] - 2026-08-18 ### Added diff --git a/its/pom.xml b/its/pom.xml index 37277d6..119f9e5 100644 --- a/its/pom.xml +++ b/its/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.2-beta-1 + 1.3.0-beta-1 ../pom.xml 4.0.0 diff --git a/openapi-checks/pom.xml b/openapi-checks/pom.xml index ae89cbb..7cfac7d 100644 --- a/openapi-checks/pom.xml +++ b/openapi-checks/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.2-beta-1 + 1.3.0-beta-1 ../pom.xml diff --git a/openapi-front-end/pom.xml b/openapi-front-end/pom.xml index 1d6729c..4c3b289 100644 --- a/openapi-front-end/pom.xml +++ b/openapi-front-end/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.2-beta-1 + 1.3.0-beta-1 ../pom.xml diff --git a/openapi-test-tools/pom.xml b/openapi-test-tools/pom.xml index 8ed2d72..b6f012d 100644 --- a/openapi-test-tools/pom.xml +++ b/openapi-test-tools/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.2-beta-1 + 1.3.0-beta-1 ../pom.xml diff --git a/pom.xml b/pom.xml index c47f9ce..b58cf45 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.2-beta-1 + 1.3.0-beta-1 pom SonarOpenAPI diff --git a/sonar-openapi-plugin/pom.xml b/sonar-openapi-plugin/pom.xml index e365ba6..0a6a333 100644 --- a/sonar-openapi-plugin/pom.xml +++ b/sonar-openapi-plugin/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.2.2-beta-1 + 1.3.0-beta-1 ../pom.xml From 5c6b760b3dc862062039d5443305dbd9dd6e2f76 Mon Sep 17 00:00:00 2001 From: Sebastian Diaz Torres Date: Wed, 26 Aug 2026 12:54:32 -0500 Subject: [PATCH 4/7] fix: Revert workflows settings to try --- .github/workflows/maven.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 57b0cab..efe3046 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -23,16 +23,10 @@ jobs: cache: maven - name: Build, Test and Coverage run: mvn -B verify --file pom.xml - - name: Set up JDK 21 for Sonar - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - cache: maven - name: SonarCloud Analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.11.0.3922:sonar -Dsonar.token=$SONAR_TOKEN + run: mvn sonar:sonar -Dsonar.token=$SONAR_TOKEN - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@v4 From 2efdf3ba766861845f4068bc910275148cfa6346 Mon Sep 17 00:00:00 2001 From: Sebastian Diaz Torres Date: Wed, 26 Aug 2026 12:56:43 -0500 Subject: [PATCH 5/7] fix: Recover config for workflow --- .github/workflows/maven.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index efe3046..57b0cab 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -23,10 +23,16 @@ jobs: cache: maven - name: Build, Test and Coverage run: mvn -B verify --file pom.xml + - name: Set up JDK 21 for Sonar + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven - name: SonarCloud Analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn sonar:sonar -Dsonar.token=$SONAR_TOKEN + run: mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.11.0.3922:sonar -Dsonar.token=$SONAR_TOKEN - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@v4 From 378af595c362b701e70cb4fd4a0168bd30eae128 Mon Sep 17 00:00:00 2001 From: Melsy Huamani Date: Tue, 1 Sep 2026 12:00:05 -0500 Subject: [PATCH 6/7] fix: analyse documents declaring an unsupported OpenAPI version instead of skipping them --- CHANGELOG.md | 6 ++++ its/pom.xml | 2 +- openapi-checks/pom.xml | 2 +- openapi-front-end/pom.xml | 2 +- .../dosonarapi/api/v2/OpenApi2Grammar.java | 2 +- .../dosonarapi/api/v3/OpenApi3Grammar.java | 2 +- .../dosonarapi/api/v31/OpenApi31Grammar.java | 2 +- .../dosonarapi/api/v32/OpenApi32Grammar.java | 2 +- openapi-test-tools/pom.xml | 2 +- pom.xml | 2 +- sonar-openapi-plugin/pom.xml | 2 +- .../dosonarapi/plugin/OpenApiAnalyzer.java | 34 ++++++------------- .../plugin/OpenApiScannerSensorTest.java | 26 ++++++++++++++ .../sensor/unsupported-openapi-version.yaml | 29 ++++++++++++++++ .../sensor/unsupported-swagger-version.yaml | 24 +++++++++++++ 15 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 sonar-openapi-plugin/src/test/resources/sensor/unsupported-openapi-version.yaml create mode 100644 sonar-openapi-plugin/src/test/resources/sensor/unsupported-swagger-version.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index e3dab72..10f2d51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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.0-beta-2] - 2026-09-01 + +### Fixed + +- An unsupported value in `openapi` / `swagger` no longer discards the whole file: the analysis reported success with zero issues from every rule. The document is now analysed with the closest known grammar. + ## [1.3.0-beta-1] - 2026-08-18 ### Added diff --git a/its/pom.xml b/its/pom.xml index 119f9e5..311f079 100644 --- a/its/pom.xml +++ b/its/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-1 + 1.3.0-beta-2 ../pom.xml 4.0.0 diff --git a/openapi-checks/pom.xml b/openapi-checks/pom.xml index 7cfac7d..162df78 100644 --- a/openapi-checks/pom.xml +++ b/openapi-checks/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-1 + 1.3.0-beta-2 ../pom.xml diff --git a/openapi-front-end/pom.xml b/openapi-front-end/pom.xml index 4c3b289..3865c8f 100644 --- a/openapi-front-end/pom.xml +++ b/openapi-front-end/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-1 + 1.3.0-beta-2 ../pom.xml diff --git a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v2/OpenApi2Grammar.java b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v2/OpenApi2Grammar.java index 5933bb1..5991a58 100644 --- a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v2/OpenApi2Grammar.java +++ b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v2/OpenApi2Grammar.java @@ -67,7 +67,7 @@ public static YamlGrammarBuilder create() { b.setRootRule(ROOT); b.rule(ROOT).is(b.object( - b.mandatoryProperty("swagger", "2.0"), + b.mandatoryProperty("swagger", b.scalar()), b.mandatoryProperty("info", INFO), b.property("host", b.string()), b.property("basePath", b.string()), diff --git a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java index 38156ed..8112fb4 100644 --- a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java +++ b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v3/OpenApi3Grammar.java @@ -83,7 +83,7 @@ public static YamlGrammarBuilder create() { b.setRootRule(ROOT); b.rule(ROOT).is(b.object( - b.mandatoryProperty("openapi", b.firstOf("3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4")), + b.mandatoryProperty("openapi", b.scalar()), b.mandatoryProperty("info", INFO), b.property("servers", b.array(SERVER)), b.mandatoryProperty("paths", PATHS), diff --git a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java index 74c01ef..051fd25 100644 --- a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java +++ b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v31/OpenApi31Grammar.java @@ -89,7 +89,7 @@ public static YamlGrammarBuilder create() { b.setRootRule(ROOT); b.rule(ROOT).is(b.object( - b.mandatoryProperty("openapi", b.firstOf("3.1.0", "3.1.1", "3.1.2")), + b.mandatoryProperty("openapi", b.scalar()), b.mandatoryProperty("info", INFO), b.property("jsonSchemaDialect", b.string()), b.property("servers", b.array(SERVER)), diff --git a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java index 3fb0e9e..afc9ce3 100644 --- a/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java +++ b/openapi-front-end/src/main/java/org/apiaddicts/apitools/dosonarapi/api/v32/OpenApi32Grammar.java @@ -90,7 +90,7 @@ public static YamlGrammarBuilder create() { b.setRootRule(ROOT); b.rule(ROOT).is(b.object( - b.mandatoryProperty("openapi", "3.2.0"), + b.mandatoryProperty("openapi", b.scalar()), b.mandatoryProperty("info", INFO), b.property("$self", b.string()), b.property("jsonSchemaDialect", b.string()), diff --git a/openapi-test-tools/pom.xml b/openapi-test-tools/pom.xml index b6f012d..380027b 100644 --- a/openapi-test-tools/pom.xml +++ b/openapi-test-tools/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-1 + 1.3.0-beta-2 ../pom.xml diff --git a/pom.xml b/pom.xml index b58cf45..60878a0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-1 + 1.3.0-beta-2 pom SonarOpenAPI diff --git a/sonar-openapi-plugin/pom.xml b/sonar-openapi-plugin/pom.xml index 0a6a333..c131549 100644 --- a/sonar-openapi-plugin/pom.xml +++ b/sonar-openapi-plugin/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-1 + 1.3.0-beta-2 ../pom.xml diff --git a/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java b/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java index 5f4fe9d..503c9d6 100644 --- a/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java +++ b/sonar-openapi-plugin/src/main/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiAnalyzer.java @@ -109,24 +109,14 @@ public void scanFiles() { } } - private static boolean isV3Version(JsonNode openapiNode) { - if (openapiNode.isMissing()) return false; - String v = openapiNode.getTokenValue(); - return "3.0.0".equals(v) || "3.0.1".equals(v) || "3.0.2".equals(v) || "3.0.3".equals(v) || "3.0.4".equals(v); - } - - private static boolean isV31Version(JsonNode openapiNode) { - if (openapiNode.isMissing()) return false; - String v = openapiNode.getTokenValue(); - return "3.1.0".equals(v) || "3.1.1".equals(v) || "3.1.2".equals(v); - } + private YamlParser selectParser(JsonNode swaggerNode, JsonNode openapiNode) { + if (!swaggerNode.isMissing()) return OpenApiParser.createV2(configuration); - private YamlParser selectParser(boolean isV2, boolean isV3, boolean isV31, boolean isV32) { - if (isV2) return OpenApiParser.createV2(configuration); - if (isV32) return OpenApiParser.createV32(configuration); - if (isV31) return OpenApiParser.createV31(configuration); - if (isV3) return OpenApiParser.createV3(configuration); - return null; + String version = openapiNode.isMissing() ? null : openapiNode.getTokenValue(); + if (version == null) return OpenApiParser.createV3(configuration); + if (version.startsWith("3.2")) return OpenApiParser.createV32(configuration); + if (version.startsWith("3.1")) return OpenApiParser.createV31(configuration); + return OpenApiParser.createV3(configuration); } private void scanFile(InputFile inputFile) { @@ -136,13 +126,11 @@ private void scanFile(InputFile inputFile) { String content = getContent(inputFile); if (!content.contains("swagger") && !content.contains("openapi")) return; JsonNode rootNode = OpenApiParser.createGeneric(configuration).parse(content); - boolean isV2 = !rootNode.at("/swagger").isMissing(); + JsonNode swaggerNode = rootNode.at("/swagger"); JsonNode openapiNode = rootNode.at("/openapi"); - boolean isV3 = isV3Version(openapiNode); - boolean isV31 = isV31Version(openapiNode); - boolean isV32 = !openapiNode.isMissing() && openapiNode.getTokenValue().equals("3.2.0"); - YamlParser targetParser = selectParser(isV2, isV3, isV31, isV32); - if (targetParser == null) return; + + if (swaggerNode.isMissing() && openapiNode.isMissing()) return; + YamlParser targetParser = selectParser(swaggerNode, openapiNode); visitorContext = new OpenApiVisitorContext(targetParser.parse(content), targetParser.getIssues(), openApiFile); saveMeasures(inputFile, visitorContext); diff --git a/sonar-openapi-plugin/src/test/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiScannerSensorTest.java b/sonar-openapi-plugin/src/test/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiScannerSensorTest.java index 8e87685..12a79c1 100644 --- a/sonar-openapi-plugin/src/test/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiScannerSensorTest.java +++ b/sonar-openapi-plugin/src/test/java/org/apiaddicts/apitools/dosonarapi/plugin/OpenApiScannerSensorTest.java @@ -250,6 +250,32 @@ public void test_folder() { System.out.println(errorFiles); } + @Test + public void unsupported_openapi_version_still_runs_rules() { + activeRules = (new ActiveRulesBuilder()) + .create(RuleKey.of(CheckList.YAML_REPOSITORY_KEY, "PathMaskerading")) + .activate() + .build(); + + inputFile("unsupported-openapi-version.yaml"); + sensor().execute(context); + + assertThat(context.allIssues()).hasSize(1); + } + + @Test + public void unsupported_swagger_version_still_runs_rules() { + activeRules = (new ActiveRulesBuilder()) + .create(RuleKey.of(CheckList.YAML_REPOSITORY_KEY, "PathMaskerading")) + .activate() + .build(); + + inputFile("unsupported-swagger-version.yaml"); + sensor().execute(context); + + assertThat(context.allIssues()).hasSize(1); + } + @Test public void cancelled_analysis() { InputFile inputFile = inputFile("file1.yaml"); diff --git a/sonar-openapi-plugin/src/test/resources/sensor/unsupported-openapi-version.yaml b/sonar-openapi-plugin/src/test/resources/sensor/unsupported-openapi-version.yaml new file mode 100644 index 0000000..54ac061 --- /dev/null +++ b/sonar-openapi-plugin/src/test/resources/sensor/unsupported-openapi-version.yaml @@ -0,0 +1,29 @@ +openapi: "1.1.3" +info: + version: 1.0.0 + title: Swagger Petstore +paths: + /pets/{petId}: + get: + responses: + '200': + description: success + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + /pets/1234: + get: + responses: + '200': + description: success + content: + 'application/json': + schema: + $ref: '#/components/schemas/Pet' +components: + schemas: + Pet: + type: object diff --git a/sonar-openapi-plugin/src/test/resources/sensor/unsupported-swagger-version.yaml b/sonar-openapi-plugin/src/test/resources/sensor/unsupported-swagger-version.yaml new file mode 100644 index 0000000..7313414 --- /dev/null +++ b/sonar-openapi-plugin/src/test/resources/sensor/unsupported-swagger-version.yaml @@ -0,0 +1,24 @@ +swagger: "1.2" +info: + version: 1.0.0 + title: Swagger Petstore +paths: + /pets/{petId}: + get: + responses: + '200': + description: success + schema: + type: array + items: + $ref: '#/definitions/Pet' + /pets/1234: + get: + responses: + '200': + description: success + schema: + $ref: '#/definitions/Pet' +definitions: + Pet: + type: object From 7c7588c685d5718c6d6adc343a0591bb3c16f0a3 Mon Sep 17 00:00:00 2001 From: Sebastian Diaz Torres Date: Thu, 10 Sep 2026 10:59:46 -0500 Subject: [PATCH 7/7] RELEASE: 1.3.0 --- CHANGELOG.md | 10 ++++++++++ its/pom.xml | 2 +- openapi-checks/pom.xml | 2 +- openapi-front-end/pom.xml | 2 +- openapi-test-tools/pom.xml | 2 +- pom.xml | 2 +- sonar-openapi-plugin/pom.xml | 2 +- 7 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10f2d51..5865ab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ 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.0] - 2026-09-10 + +### Fixed + +- An unsupported value in `openapi` / `swagger` no longer discards the whole file: the analysis reported success with zero issues from every rule. The document is now analysed with the closest known grammar. + +### Added + +- Accept OpenAPI `3.0.4`, `3.1.1` and `3.1.2` in version dispatch and the v3/v3.1/v3.2 grammars. + ## [1.3.0-beta-2] - 2026-09-01 ### Fixed diff --git a/its/pom.xml b/its/pom.xml index 311f079..6f01c04 100644 --- a/its/pom.xml +++ b/its/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-2 + 1.3.0 ../pom.xml 4.0.0 diff --git a/openapi-checks/pom.xml b/openapi-checks/pom.xml index 162df78..e147837 100644 --- a/openapi-checks/pom.xml +++ b/openapi-checks/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-2 + 1.3.0 ../pom.xml diff --git a/openapi-front-end/pom.xml b/openapi-front-end/pom.xml index 3865c8f..2e00ead 100644 --- a/openapi-front-end/pom.xml +++ b/openapi-front-end/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-2 + 1.3.0 ../pom.xml diff --git a/openapi-test-tools/pom.xml b/openapi-test-tools/pom.xml index 380027b..7060469 100644 --- a/openapi-test-tools/pom.xml +++ b/openapi-test-tools/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-2 + 1.3.0 ../pom.xml diff --git a/pom.xml b/pom.xml index 60878a0..213f7c9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-2 + 1.3.0 pom SonarOpenAPI diff --git a/sonar-openapi-plugin/pom.xml b/sonar-openapi-plugin/pom.xml index c131549..bfc2a74 100644 --- a/sonar-openapi-plugin/pom.xml +++ b/sonar-openapi-plugin/pom.xml @@ -5,7 +5,7 @@ org.apiaddicts.apitools.dosonarapi dosonarapi - 1.3.0-beta-2 + 1.3.0 ../pom.xml