Skip to content
Open
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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ 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.7.0-beta-1] - 2026-09-10

### Fixed

- OAR041 - UndefinedAuthTypeForWso2Scope - Fixed the `x-aut-type` typo in the HTML examples (should be `x-auth-type`) and rewrote the Spanish description, which described an unrelated scope-catalog structure instead of the actual check.
- OAR043 - ParsingError - Rewrote the English/Spanish HTML docs with real examples, expanded the JSON titles, and removed the orphaned `core/OAR043.*` resources (not loaded by any registered rule group).
- `tools/IssueDumper.java` - Now recovers from a `ValidationException` during test scanning for `OAR043ParsingErrorCheck`, so schema-invalid fixtures can be cross-checked against Spectral instead of crashing the harness.
- OAR005 - UndefinedWso2ScopeUse - Resolves `$ref`s on `x-wso2-security`/scopes and accepts map-form `x-wso2-scopes`, plus all null spellings for `x-scope`.
- OAR009 / OAR010 - DefaultRequestMediaType / DefaultResponseMediaType - Media type comparisons are now case-insensitive, matching Spectral.
- OAR007 - UndefinedResponseMediaType - Fixed the rule description, which wrongly described request media types (`consumes`) instead of response ones (`produces`).
- OAR026 - TotalParameterDefaultValue - Rewritten to match Spectral: only checks `GET`/`in: query` `$total` parameters, resolves `$ref`s, and no longer flags a missing `default`.
- OAR031 - Examples - Property checks now only cover schemas reachable from the path, traverse `allOf`/`oneOf`/`anyOf`, interpolate the actual name in messages, and fix several line-anchoring and OAS2-exemption divergences from Spectral.

## [1.6.0] - 2026-09-10

Recopilado de `1.6.0-beta-1` a `1.6.0-beta-5`.
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.6.0</version>
<version>1.7.0-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 @@ -10,7 +10,6 @@
import apiaddicts.sonar.openapi.utils.JsonNodeUtils;
import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

Expand All @@ -33,20 +32,12 @@ protected JsonNode scopesKeyNode() {
}

private void visitV2NV3Node(JsonNode node) {
JsonNode securityNode = node.get("x-wso2-security");
if (!securityNode.isMissing()) securityNode = JsonNodeUtils.resolve(securityNode);
JsonNode apimNode = securityNode.get("apim");
JsonNode scopesNode = apimNode.get("x-wso2-scopes");
scopesKeyNode = JsonNodeUtils.propertyKey(apimNode, "x-wso2-scopes");
JsonNode apimNode = JsonNodeUtils.getWso2ApimNode(node);
JsonNode scopesNode = apimNode.get(JsonNodeUtils.WSO2_SCOPES);
scopesKeyNode = JsonNodeUtils.propertyKey(apimNode, JsonNodeUtils.WSO2_SCOPES);
visitScopesNode(scopesNode);
if (scopesNode.isMissing() || scopesNode.isNull()) return;
List<JsonNode> rawScopes = scopesNode.isObject()
? new ArrayList<>(scopesNode.propertyMap().values())
: scopesNode.elements();
List<JsonNode> scopes = new ArrayList<>(rawScopes.size());
for (JsonNode scope : rawScopes) {
scopes.add(JsonNodeUtils.resolve(scope));
}
List<JsonNode> scopes = JsonNodeUtils.getWso2Scopes(scopesNode);
visitScopes(scopes);
scopes.forEach(this::visitScope);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
package apiaddicts.sonar.openapi.checks.apim.wso2;

import com.google.common.collect.ImmutableSet;
import com.sonar.sslr.api.Token;
import org.sonar.check.Rule;
import apiaddicts.sonar.openapi.utils.JsonNodeUtils;
import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode;

import java.util.List;
import java.util.Map;
import java.util.Set;

@Rule(key = OAR002ValidWso2ScopesCheck.KEY)
public class OAR002ValidWso2ScopesCheck extends AbstractWso2ScopesCheck {

public static final String KEY = "OAR002";
private static final String MESSAGE = "OAR002.error";
private static final String MESSAGE_PROP = "OAR002.error-property";
private static final Set<String> NULL_SPELLINGS = ImmutableSet.of("~", "Null", "NULL");

private JsonNode scopesNode;

Expand Down Expand Up @@ -63,15 +59,9 @@ private JsonNode scopeLocation(JsonNode scope) {
}

private boolean isEmpty(JsonNode property) {
if (isNullScalar(property)) return true;
if (JsonNodeUtils.isNullScalar(property)) return true;
if (property.isArray()) return property.elements().isEmpty();
if (property.isObject()) return property.propertyMap().isEmpty();
return property.getTokenValue().trim().equals("");
}

private boolean isNullScalar(JsonNode property) {
if (property.isNull()) return true;
Token token = property.getToken();
return token != null && NULL_SPELLINGS.contains(token.getOriginalValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

import com.sonar.sslr.api.AstNode;
import org.sonar.check.Rule;
import apiaddicts.sonar.openapi.utils.JsonNodeUtils;
import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode;

import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;

@Rule(key = OAR005UndefinedWso2ScopeUseCheck.KEY)
public class OAR005UndefinedWso2ScopeUseCheck
extends AbstractWso2OperationCheck {
Expand All @@ -26,18 +24,13 @@ protected void visitFile(JsonNode root) {

private Set<String> getScopes(JsonNode root) {

JsonNode scopes = root
.get("x-wso2-security")
.get("apim")
.get("x-wso2-scopes");

if (scopes.isMissing() || scopes.isNull()) {
return Collections.emptySet();
}
JsonNode scopes = JsonNodeUtils
.getWso2ApimNode(root)
.get(JsonNodeUtils.WSO2_SCOPES);

return scopes.elements().stream()
return JsonNodeUtils.getWso2Scopes(scopes).stream()
.map(node -> node.get("name"))
.filter(node -> !node.isMissing() && !node.isNull())
.filter(node -> !node.isMissing() && !JsonNodeUtils.isNullScalar(node))
.map(AstNode::getTokenValue)
.collect(Collectors.toSet());
}
Expand All @@ -49,12 +42,8 @@ protected void visitOperationNode(JsonNode node) {

if (scopeNode.isMissing()) return;

String scope = scopeNode.isNull()
? null
: scopeNode.getTokenValue();

if (isNull(scope) || !definedScopes.contains(scope)) {
if (JsonNodeUtils.isNullScalar(scopeNode) || !definedScopes.contains(scopeNode.getTokenValue())) {
addIssue(KEY, translate(MESSAGE), scopeNode);
}
}
}
}
Loading