From 10f2429db316e5d64abacdbb79181fe1799651f1 Mon Sep 17 00:00:00 2001 From: Melsy Huamani Date: Mon, 27 Jul 2026 18:58:14 -0500 Subject: [PATCH] fix: oar044 media type validation --- CHANGELOG.md | 6 ++++++ pom.xml | 2 +- .../checks/format/OAR044MediaTypeCheck.java | 21 ++++++++++--------- .../checks/v2/format/OAR044/media-type.json | 4 ++-- .../checks/v2/format/OAR044/media-type.yaml | 3 +++ .../checks/v3/format/OAR044/media-type.json | 12 ++++++++--- .../checks/v3/format/OAR044/media-type.yaml | 8 ++++++- .../checks/v31/format/OAR044/media-type.json | 12 ++++++++--- .../checks/v31/format/OAR044/media-type.yaml | 8 ++++++- .../checks/v32/format/OAR044/media-type.json | 12 ++++++++--- .../checks/v32/format/OAR044/media-type.yaml | 8 ++++++- 11 files changed, 71 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21481194..9a1e2ead 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.5.0-beta-5] - 2026-07-27 + +### Fixed + +- OAR044 - MediaTypeCheck - Media type parameters now follow RFC 9110 (charset without space, other parameter names, multiple parameters); type/subtype can no longer start with `.`. + ## [1.5.0-beta-4] - 2026-07-14 ### Fixed diff --git a/pom.xml b/pom.xml index 161983e8..2942fd55 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.apiaddicts.apitools.dosonarapi sonaropenapi-rules-community - 1.5.0-beta-4 + 1.5.0-beta-5 sonar-plugin SonarQube OpenAPI Community Rules diff --git a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java index 15d3a523..39656827 100644 --- a/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java +++ b/src/main/java/apiaddicts/sonar/openapi/checks/format/OAR044MediaTypeCheck.java @@ -44,19 +44,20 @@ public class OAR044MediaTypeCheck extends BaseCheck { protected static final String MESSAGE_V3 = "OAR044.error.v3"; private final ExternalRefHandler handleExternalRef = new ExternalRefHandler(); + private static final String RESTRICTED_NAME = "[a-zA-Z0-9][a-zA-Z0-9.!#$&^_+\\-]*"; + private static final String OWS = "[ \\t]*"; + private static final String TOKEN = "[a-zA-Z0-9!#$%&'*+\\-.^_`|~]+"; + private static final String QUOTED_STRING = "\"(?:[^\"\\\\]|\\\\.)*\""; + private static final String PARAMETERS = + "(?:" + OWS + ";" + OWS + TOKEN + "=(?:" + TOKEN + "|" + QUOTED_STRING + "))*"; + @VisibleForTesting static final Pattern MIME_TYPE_PATTERN = Pattern.compile( - "[a-zA-Z0-9.][a-zA-Z0-9.!#$&_^+\\-]+/" + - "[a-zA-Z0-9.][a-zA-Z0-9.!#$&_^+\\-]+" + - "(; charset=[a-zA-Z0-9_\\-]+)?" + RESTRICTED_NAME + "/" + RESTRICTED_NAME + PARAMETERS ); @VisibleForTesting static final Pattern MEDIA_RANGE_PATTERN = Pattern.compile( - "(\\*|[a-zA-Z0-9.][a-zA-Z0-9.!#$&_^+\\-]+)/" + - "(\\*|" + - "[a-zA-Z0-9.][a-zA-Z0-9.!#$&_^+\\-]+" + - "(; charset=[a-zA-Z0-9_\\-]+)?" + - ")" + "(\\*|" + RESTRICTED_NAME + ")/(\\*|" + RESTRICTED_NAME + ")" + PARAMETERS ); @Override @@ -114,8 +115,8 @@ private void verifyParameterContent(JsonNode node) { for (JsonNode property : properties.values()) { JsonNode keyNode = property.key(); String key = keyNode.getTokenValue(); - if (!MIME_TYPE_PATTERN.matcher(key).matches()) { - addIssue(CHECK_KEY, translate(MESSAGE_V2), keyNode); + if (!MEDIA_RANGE_PATTERN.matcher(key).matches()) { + addIssue(CHECK_KEY, translate(MESSAGE_V3), keyNode); } } } diff --git a/src/test/resources/checks/v2/format/OAR044/media-type.json b/src/test/resources/checks/v2/format/OAR044/media-type.json index 216fca4c..c785305c 100644 --- a/src/test/resources/checks/v2/format/OAR044/media-type.json +++ b/src/test/resources/checks/v2/format/OAR044/media-type.json @@ -18,8 +18,8 @@ } }, "post" : { - "produces" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json", "text/csv", "image/png" ], - "consumes" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json" ], + "produces" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json", "text/csv", "image/png", "text/plain;charset=utf-8", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk" ], + "consumes" : [ "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/ld+json", "application/json; charset=utf-8; boundary=xyz" ], "responses" : { "200" : { "description" : "some operation" diff --git a/src/test/resources/checks/v2/format/OAR044/media-type.yaml b/src/test/resources/checks/v2/format/OAR044/media-type.yaml index fd2d08e0..aaabbad4 100644 --- a/src/test/resources/checks/v2/format/OAR044/media-type.yaml +++ b/src/test/resources/checks/v2/format/OAR044/media-type.yaml @@ -27,10 +27,13 @@ paths: - application/ld+json - text/csv - image/png + - text/plain;charset=utf-8 + - multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk consumes: - application/vnd.ms-excel - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - application/ld+json + - application/json; charset=utf-8; boundary=xyz responses: '200': description: some operation \ No newline at end of file diff --git a/src/test/resources/checks/v3/format/OAR044/media-type.json b/src/test/resources/checks/v3/format/OAR044/media-type.json index 3d3b5d7a..560ca700 100644 --- a/src/test/resources/checks/v3/format/OAR044/media-type.json +++ b/src/test/resources/checks/v3/format/OAR044/media-type.json @@ -19,10 +19,11 @@ "name" : "someParam", "in" : "query", "content" : { - "application" : { }, # Noncompliant {{OAR044: Declared mime type should conform to RFC6838}} + "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + "text/*" : { }, "text/plain" : { } } - }, + }, { "name" : "otherParam", "in" : "path" @@ -32,12 +33,17 @@ "requestBody" : { "content" : { "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + ".text/plain" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} "text/*" : { }, "application/vnd.ms-excel" : { }, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { }, "application/ld+json" : { }, "image/*" : { }, - "*/*" : { } + "*/*" : { }, + "text/plain;charset=utf-8" : { }, + "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk" : { }, + "multipart/form-data; boundary=\"----abc 123\"" : { }, + "application/json; charset=utf-8; boundary=xyz" : { } } }, "responses" : { diff --git a/src/test/resources/checks/v3/format/OAR044/media-type.yaml b/src/test/resources/checks/v3/format/OAR044/media-type.yaml index 60d8c85a..91373ff4 100644 --- a/src/test/resources/checks/v3/format/OAR044/media-type.yaml +++ b/src/test/resources/checks/v3/format/OAR044/media-type.yaml @@ -14,7 +14,8 @@ paths: - name: someParam in: query content: - 'application': {} # Noncompliant {{OAR044: Declared mime type should conform to RFC6838}} + 'application': {} # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + 'text/*': {} 'text/plain': {} # invalid (only 1 content allowed by spec), but should not be caught by this rule - name: otherParam in: path @@ -22,12 +23,17 @@ paths: requestBody: content: 'application': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + '.text/plain': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} 'text/*': { } 'application/vnd.ms-excel': {} 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {} 'application/ld+json': {} 'image/*': {} '*/*': {} + 'text/plain;charset=utf-8': {} + 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk': {} + 'multipart/form-data; boundary="----abc 123"': {} + 'application/json; charset=utf-8; boundary=xyz': {} responses: '200': description: some operation diff --git a/src/test/resources/checks/v31/format/OAR044/media-type.json b/src/test/resources/checks/v31/format/OAR044/media-type.json index 05232934..97dd17e6 100644 --- a/src/test/resources/checks/v31/format/OAR044/media-type.json +++ b/src/test/resources/checks/v31/format/OAR044/media-type.json @@ -19,10 +19,11 @@ "name" : "someParam", "in" : "query", "content" : { - "application" : { }, # Noncompliant {{OAR044: Declared mime type should conform to RFC6838}} + "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + "text/*" : { }, "text/plain" : { } } - }, + }, { "name" : "otherParam", "in" : "path" @@ -32,12 +33,17 @@ "requestBody" : { "content" : { "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + ".text/plain" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} "text/*" : { }, "application/vnd.ms-excel" : { }, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { }, "application/ld+json" : { }, "image/*" : { }, - "*/*" : { } + "*/*" : { }, + "text/plain;charset=utf-8" : { }, + "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk" : { }, + "multipart/form-data; boundary=\"----abc 123\"" : { }, + "application/json; charset=utf-8; boundary=xyz" : { } } }, "responses" : { diff --git a/src/test/resources/checks/v31/format/OAR044/media-type.yaml b/src/test/resources/checks/v31/format/OAR044/media-type.yaml index 71f903d8..1de0edc8 100644 --- a/src/test/resources/checks/v31/format/OAR044/media-type.yaml +++ b/src/test/resources/checks/v31/format/OAR044/media-type.yaml @@ -14,7 +14,8 @@ paths: - name: someParam in: query content: - 'application': {} # Noncompliant {{OAR044: Declared mime type should conform to RFC6838}} + 'application': {} # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + 'text/*': {} 'text/plain': {} # invalid (only 1 content allowed by spec), but should not be caught by this rule - name: otherParam in: path @@ -22,12 +23,17 @@ paths: requestBody: content: 'application': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + '.text/plain': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} 'text/*': { } 'application/vnd.ms-excel': {} 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {} 'application/ld+json': {} 'image/*': {} '*/*': {} + 'text/plain;charset=utf-8': {} + 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk': {} + 'multipart/form-data; boundary="----abc 123"': {} + 'application/json; charset=utf-8; boundary=xyz': {} responses: '200': description: some operation diff --git a/src/test/resources/checks/v32/format/OAR044/media-type.json b/src/test/resources/checks/v32/format/OAR044/media-type.json index 0251e212..0b41954d 100644 --- a/src/test/resources/checks/v32/format/OAR044/media-type.json +++ b/src/test/resources/checks/v32/format/OAR044/media-type.json @@ -19,10 +19,11 @@ "name" : "someParam", "in" : "query", "content" : { - "application" : { }, # Noncompliant {{OAR044: Declared mime type should conform to RFC6838}} + "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + "text/*" : { }, "text/plain" : { } } - }, + }, { "name" : "otherParam", "in" : "path" @@ -32,12 +33,17 @@ "requestBody" : { "content" : { "application" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + ".text/plain" : { }, # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} "text/*" : { }, "application/vnd.ms-excel" : { }, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : { }, "application/ld+json" : { }, "image/*" : { }, - "*/*" : { } + "*/*" : { }, + "text/plain;charset=utf-8" : { }, + "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk" : { }, + "multipart/form-data; boundary=\"----abc 123\"" : { }, + "application/json; charset=utf-8; boundary=xyz" : { } } }, "responses" : { diff --git a/src/test/resources/checks/v32/format/OAR044/media-type.yaml b/src/test/resources/checks/v32/format/OAR044/media-type.yaml index 6e1cbd7d..7b19fa8f 100644 --- a/src/test/resources/checks/v32/format/OAR044/media-type.yaml +++ b/src/test/resources/checks/v32/format/OAR044/media-type.yaml @@ -14,7 +14,8 @@ paths: - name: someParam in: query content: - 'application': {} # Noncompliant {{OAR044: Declared mime type should conform to RFC6838}} + 'application': {} # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + 'text/*': {} 'text/plain': {} # invalid (only 1 content allowed by spec), but should not be caught by this rule - name: otherParam in: path @@ -22,12 +23,17 @@ paths: requestBody: content: 'application': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} + '.text/plain': { } # Noncompliant {{OAR044: Declared media type range should conform to RFC7231}} 'text/*': { } 'application/vnd.ms-excel': {} 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': {} 'application/ld+json': {} 'image/*': {} '*/*': {} + 'text/plain;charset=utf-8': {} + 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk': {} + 'multipart/form-data; boundary="----abc 123"': {} + 'application/json; charset=utf-8; boundary=xyz': {} responses: '200': description: some operation