Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.5.1-beta-1] - 2026-08-04

### Fixed

- OAR014 / OAR015 - ResourceLevel - Issue message now interpolates the configured level values (min-level/max-level for OAR014, max-level-allowed for OAR015).
- OAR004 / OAR040 - Wso2Scopes - Issue message now includes the configured `pattern` (passed through `AbstractPatternWso2ScopesCheck`).
- OAR038 - StandardCreateResponse - Issue message now interpolates the configured `data-property` instead of the hardcoded `data`.
- OAR082 - BinaryOrByteFormat - Issue message now shows the configured `fields-to-apply`.
- OAR085 - OpenAPIVersion - Issue message now shows the configured `valid-versions`.
- OAR037 - StringFormat - Issue message now interpolates the configured `formats-allowed`.


## [1.5.0] - 2026-07-28

### Added
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
<artifactId>sonaropenapi-rules-community</artifactId>
<version>1.5.0</version>
<version>1.5.1-beta-1</version>
<packaging>sonar-plugin</packaging>

<name>SonarQube OpenAPI Community Rules</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,19 @@ protected void visitScope(JsonNode scope) {
if (fieldNode == null || fieldNode.isNull() || fieldNode.isMissing())
return;

String patternStr = getPatternStr() != null ? getPatternStr() : defaultPatternValue;
List<JsonNode> elements = fieldNode.elements();
if (!elements.isEmpty()) {
for (JsonNode element : elements) {
String roleText = element.getTokenValue();
if (roleText != null && !pattern.matcher(roleText).matches()) {
addIssue(ruleKey, translate(messageKey), element);
addIssue(ruleKey, translate(messageKey, patternStr), element);
}
}
} else {
String fieldText = fieldNode.getTokenValue();
if (fieldText != null && !pattern.matcher(fieldText).matches()) {
addIssue(ruleKey, translate(messageKey), fieldNode);
addIssue(ruleKey, translate(messageKey, patternStr), fieldNode);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ public void validate(String type, String format, JsonNode typeNode, JsonNode nod
.map(f -> f.trim().toLowerCase())
.collect(Collectors.toSet());
if (!validFormats.contains(format.toLowerCase())) {
addIssue(KEY, translate(MESSAGE), typeNode.key());
addIssue(KEY, translate(MESSAGE, formatsAllowed), typeNode.key());
}
return;
}

if (!hasValidPattern(node)) {
addIssue(KEY, translate(MESSAGE), typeNode.key());
addIssue(KEY, translate(MESSAGE, formatsAllowed), typeNode.key());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

public abstract class AbstractResourceLevelCheck extends BaseCheck {

private static final String MESSAGE = "generic.path-level";

private String key;

protected AbstractResourceLevelCheck(String key) {
Expand All @@ -31,9 +29,13 @@ public Set<AstNodeType> subscribedKinds() {
@Override
public void visitNode(JsonNode node) {
String path = node.key().getTokenValue();
if (matchLevel(path)) addIssue(key, translate(MESSAGE), node.key());
if (matchLevel(path)) addIssue(key, translate(messageKey(), messageArgs()), node.key());
}

protected abstract String messageKey();

protected abstract Object[] messageArgs();

private boolean matchLevel(String path) {
long literalCount = Stream.of(path.split("/"))
.filter(s -> !s.trim().isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,14 @@ public OAR014ResourceLevelWithinNonSuggestedRangeCheck() {
boolean matchLevel(long level) {
return minLevel <= level && level <= maxLevel;
}

@Override
protected String messageKey() {
return "OAR014.error";
}

@Override
protected Object[] messageArgs() {
return new Object[] { minLevel, maxLevel };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,14 @@ public OAR015ResourceLevelMaxAllowedCheck() {
boolean matchLevel(long level) {
return maxLevelAllowed < level;
}

@Override
protected String messageKey() {
return "OAR015.error";
}

@Override
protected Object[] messageArgs() {
return new Object[] { maxLevelAllowed };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ protected void visitV2ExplicitNode(JsonNode node) {
addIssue(KEY, translate("OAR038.error-required-one-property"), entry.getValue().key());
}
} else {
addIssue(KEY, translate("OAR038.error"), entry.getValue().key());
addIssue(KEY, translate("OAR038.error", dataNode), entry.getValue().key());
}
}

if (properties.isEmpty()) {
addIssue(KEY, translate("OAR038.error"), schemaNode.key());
addIssue(KEY, translate("OAR038.error", dataNode), schemaNode.key());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private void visitV2Node(JsonNode node) {
if ("string".equals(type)) {
String format = fieldNode.get("format").getTokenValue();
if (!"binary".equals(format) && !"byte".equals(format)) {
addIssue(KEY, translate(MESSAGE), typeNode.key());
addIssue(KEY, translate(MESSAGE, fieldsApply), typeNode.key());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected void visitFile(JsonNode root) {
List<String> validVersions = Arrays.asList(validVersionsStr.split(","));

if (version == null || !validVersions.contains(version)) {
addIssue(KEY, translate(MESSAGE, version), root.key());
addIssue(KEY, translate(MESSAGE, validVersionsStr), root.key());
}
}

Expand Down
14 changes: 8 additions & 6 deletions src/main/resources/messages/errors.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ OAR001.error-v3-https=Protocol https in server url is mandatory
OAR002.error=WSO2 scopes definition is wrong
OAR002.error-property=WSO2 scope ''{0}'' is required
OAR003.error=WSO2 scope ''description'' is recommended
OAR004.error=WSO2 scope roles value is not valid
OAR004.error=WSO2 scope role does not match the required pattern: {0}
OAR005.error=WSO2 scope definition does not exists
OAR008.error=Http verb ({0}) not encouraged
OAR010.error-request-body-not-allowed=requestBody not allowed with operation ''{0}''
OAR011.error=The base path and resource names with more than two words must be compliant with the standard naming convention: {0}
OAR012.error=Path params names, query params names, object names and property names with more than two words must be compliant with the standard naming convention: {0}
OAR013.error=Default response is required
OAR014.error=Resources depth level must not fall within the non-suggested range {0} to {1}
OAR015.error=Resources depth level must be smaller than or equal to {0}
OAR016.error=Numeric types requires a valid format
OAR017.error=Resource path should alternate static and parametrized parts
OAR017.error-patterns=Pattern ''{0}'' not allowed
Expand All @@ -37,12 +39,12 @@ OAR032.error=Ambiguous path parts not encouraged: {0}
OAR033.error-header-required=''{0}'' header must be required
OAR035.error=Response code {0} must be defined for operations with security schemes defined
OAR036.error=Cookie use is forbidden as a session mechanism
OAR037.error=String types require a valid format, or a valid pattern when no format is defined
OAR038.error=''data'' or ''error'' property is required
OAR037.error=String types require one of the allowed formats ({0}), or a valid pattern when no format is defined
OAR038.error=''{0}'' or ''error'' property is required
OAR038.error-required-schema=Response schema is required
OAR038.error-required-one-property=At least you have to define the identifier property
OAR039.error=Response code {0} must be defined
OAR040.error=WSO2 scope name value is non compliant with the standard
OAR040.error=WSO2 scope name does not match the required pattern: {0}
OAR041.error=WSO2 x-scope requires x-auth-type definition
OAR042.error-version=Last path part must be the API version, indicated with the prefix ''v'' and the version number as integer
OAR042.error-path-short=Path has to few parts
Expand Down Expand Up @@ -92,10 +94,10 @@ OAR078.error=All API methods must have security
OAR079.error=Paths parameters, should have not found (404) response
OAR080.error=The security scheme must be among those allowed by the organization and must be complete.
OAR081.error=Fields of type password should be string with format password
OAR082.error=The string properties of the specified parameters must define a byte or binary format.
OAR082.error=The string properties among {0} must define a byte or binary format
OAR083.error=The parameter {0} should not pass through this querystring
OAR084.error=The format {0} should not pass through this querystring
OAR085.error=The OpenAPI version should be one of the allowed by the organization
OAR085.error=The OpenAPI version must be one of: {0}
OAR086.error=Descriptions must begin with a capital letter, end with a period and not be empty
OAR087.error=Summaries must begin with a capital letter, end with a period and not be empty
OAR088.error=The $ref of a parameter must end with the suffix {0}
Expand Down
14 changes: 8 additions & 6 deletions src/main/resources/messages/errors_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ OAR001.error-v3-https=El protocolo https en la URL del servidor es obligatorio
OAR002.error=La definición de los scopes es errónea
OAR002.error-property=EL apartado ''{0}'' del scope es obligatorio
OAR003.error=Se recomienda definir el apartado ''description'' de este scope
OAR004.error=El valor del campo roles de este scope no es válido
OAR004.error=El rol del scope de WSO2 no cumple con el patrón requerido: {0}
OAR005.error=La definición de este scope no existe
OAR008.error=Verbo http ({0}) no recomendado
OAR010.error-request-body-not-allowed=requestBody no permitido con la operación ''{0}''
OAR011.error=La ruta base y los nombres de recursos con más de dos palabras deben cumplir con la convención de nombres estándar: {0}
OAR012.error=Los nombres de parámetros de ruta, parámetros de consulta, objetos y propiedades con más de dos palabras deben ajustarse a la convención de nomenclatura estándar: {0}
OAR013.error=La respuesta por defecto es obligatoria
OAR014.error=El nivel de profundidad de los recursos no debe estar dentro del rango no sugerido de {0} a {1}
OAR015.error=El nivel de profundidad de los recursos debe ser menor o igual a {0}
OAR016.error=Tipos numéricos requieren un formato válido
OAR017.error=El path del recurso debe de alternar entre partes estáticas y parametrizadas
OAR017.error-patterns=Patrón ''{0}'' no permitido
Expand All @@ -37,12 +39,12 @@ OAR032.error=Nombres de partes de path ambiguos no permitidos: {0}
OAR033.error-header-required=La cabecera ''{0}'' debe ser obligatoria
OAR035.error=El código de respuesta {0} debe estar definido cuando la operación tiene esquemas de seguridad definidos
OAR036.error=El uso de cookies está prohibido como mecanismo de sesión
OAR037.error=Las propiedades de tipo string deben definir un formato válido o, si no hay formato, un pattern válido
OAR038.error=La propiedad ''data'' o ''error'' es obligatoria
OAR037.error=Las propiedades de tipo string deben definir uno de los formatos permitidos ({0}) o, si no hay formato, un pattern válido
OAR038.error=La propiedad ''{0}'' o ''error'' es obligatoria
OAR038.error-required-schema=El esquema de respuesta es obligatorio
OAR038.error-required-one-property=Se debe de definir al menos una propiedad
OAR039.error=Código de respuesta {0} debe ser definido
OAR040.error=El nombre del scope de WSO2 no cumple con el estándar
OAR040.error=El nombre del scope de WSO2 no cumple con el patrón requerido: {0}
OAR041.error=La sección x-scope de WSO2 obliga a definir la sección x-auth-type
OAR042.error-version=La última parte de la ruta debe ser la versión de la API, indicada con el prefijo ''v'' y el número de versión como entero
OAR042.error-path-short=El path tiene muy pocas partes
Expand Down Expand Up @@ -92,10 +94,10 @@ OAR078.error=Todos los métodos de una API deben tener seguridad
OAR079.error=Los parámetros in PATH debem tener una respuesta Not Found (404)
OAR080.error=El esquema de seguridad debe ser entre los permitidos de la organización, además debe estar completo
OAR081.error=Los campos de tipo password deben ser string con formato password
OAR082.error=Las propiedades de tipo string de los parámetros especificados,deben definir un formato bite o binary
OAR082.error=Las propiedades de tipo string entre {0} deben definir un formato byte o binary
OAR083.error=El parámetro {0} no debe pasar por este querystring
OAR084.error=El formato {0} no debe pasar por este querystring
OAR085.error=La versión del OpenAPI debe estar entre los permitidos de la organización
OAR085.error=La versión del OpenAPI debe ser una de: {0}
OAR086.error=Las descripciones no pueden estar vacías, deben empezar con mayúsculas y terminar con un punto
OAR087.error=Los summary no pueden estar vacíos, deben empezar con mayúsculas y terminar con un punto
OAR088.error=El $ref de un parámetro debe terminar con el sufijo {0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"x-wso2-scopes" : [ {
"name" : "read",
"key" : "read",
"roles" : [ "ROLE_READ", "ROL€_V¡€U" ], # Noncompliant {{OAR004: WSO2 scope roles value is not valid}}
"roles" : [ "ROLE_READ", "ROL€_V¡€U" ], # Noncompliant {{OAR004: WSO2 scope role does not match the required pattern: ^[a-zA-Z0-9_\-., ]+$}}
"description" : "Allows users to read records"
} ]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ x-wso2-security:
key: read
roles:
- ROLE_READ
- ROL€_V¡€U # Noncompliant {{OAR004: WSO2 scope roles value is not valid}}
- ROL€_V¡€U # Noncompliant {{OAR004: WSO2 scope role does not match the required pattern: ^[a-zA-Z0-9_\-., ]+$}}
description: Allows users to read records
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"x-wso2-scopes" : [ {
"name" : "read",
"key" : "read",
"roles" : "ROLE_READ, ROL€_V¡€U", # Noncompliant {{OAR004: WSO2 scope roles value is not valid}}
"roles" : "ROLE_READ, ROL€_V¡€U", # Noncompliant {{OAR004: WSO2 scope role does not match the required pattern: ^[a-zA-Z0-9_\-., ]+$}}
"description" : "Allows users to read records"
} ]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ x-wso2-security:
x-wso2-scopes:
- name: read
key: read
roles: ROLE_READ, ROL€_V¡€U # Noncompliant {{OAR004: WSO2 scope roles value is not valid}}
roles: ROLE_READ, ROL€_V¡€U # Noncompliant {{OAR004: WSO2 scope role does not match the required pattern: ^[a-zA-Z0-9_\-., ]+$}}
description: Allows users to read records
8 changes: 4 additions & 4 deletions src/test/resources/checks/v2/apim/wso2/OAR040/invalid.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
"x-wso2-security" : {
"apim" : {
"x-wso2-scopes" : [ {
"name" : "app" # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
"name" : "app" # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
}, {
"name" : "app1_sc_ran" # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
"name" : "app1_sc_ran" # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
}, {
"name" : "GENE_Sc_ran" # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
"name" : "GENE_Sc_ran" # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
}, {
"name" : "X_SC_A" # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
"name" : "X_SC_A" # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
} ]
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/test/resources/checks/v2/apim/wso2/OAR040/invalid.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ paths:
x-wso2-security:
apim:
x-wso2-scopes:
- name: app # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
- name: app1_sc_ran # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
- name: GENE_Sc_ran # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
- name: X_SC_A # Noncompliant {{OAR040: WSO2 scope name value is non compliant with the standard}}
- name: app # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
- name: app1_sc_ran # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
- name: GENE_Sc_ran # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
- name: X_SC_A # Noncompliant {{OAR040: WSO2 scope name does not match the required pattern: ^[a-zA-Z]{4,}_(SC|sc)_[a-zA-Z0-9]{1,}$}}
2 changes: 1 addition & 1 deletion src/test/resources/checks/v2/format/OAR037/nested.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"type" : "object",
"properties" : {
"value" : {
"type" : "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
"type" : "string", # Noncompliant {{OAR037: String types require one of the allowed formats (date,date-time,password,byte,binary,email,uuid,uri,hostname,ipv4,ipv6,HEX,HEX(16),json,xml,base64), or a valid pattern when no format is defined}}
"format" : "YYYY-MM-DD"
},
"code" : {
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/checks/v2/format/OAR037/nested.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ paths:
type: object
properties:
value:
type: string # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
type: string # Noncompliant {{OAR037: String types require one of the allowed formats (date,date-time,password,byte,binary,email,uuid,uri,hostname,ipv4,ipv6,HEX,HEX(16),json,xml,base64), or a valid pattern when no format is defined}}
format: YYYY-MM-DD
code:
type: string
Expand Down
6 changes: 3 additions & 3 deletions src/test/resources/checks/v2/format/OAR037/plain.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
"type" : "object",
"properties" : {
"without" : {
"type" : "string" # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
"type" : "string" # Noncompliant {{OAR037: String types require one of the allowed formats (date,date-time,password,byte,binary,email,uuid,uri,hostname,ipv4,ipv6,HEX,HEX(16),json,xml,base64), or a valid pattern when no format is defined}}
},
"withPattern" : {
"type" : "string",
"pattern" : "^[A-Z]{3}-[0-9]+$"
},
"withInvalidPattern" : {
"type" : "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
"type" : "string", # Noncompliant {{OAR037: String types require one of the allowed formats (date,date-time,password,byte,binary,email,uuid,uri,hostname,ipv4,ipv6,HEX,HEX(16),json,xml,base64), or a valid pattern when no format is defined}}
"pattern" : "["
},
"date" : {
Expand Down Expand Up @@ -69,7 +69,7 @@
"format" : "ipv6"
},
"other" : {
"type" : "string", # Noncompliant {{OAR037: String types require a valid format, or a valid pattern when no format is defined}}
"type" : "string", # Noncompliant {{OAR037: String types require one of the allowed formats (date,date-time,password,byte,binary,email,uuid,uri,hostname,ipv4,ipv6,HEX,HEX(16),json,xml,base64), or a valid pattern when no format is defined}}
"format" : "YYYY-MM-DD"
}
}
Expand Down
Loading