Skip to content
Draft
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: 11 additions & 1 deletion BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@ jlink --add-modules java.base,java.naming,java.xml,java.desktop --output custom-
To build the installer with a custom JRE (for windows) use:
```bash
jpackage --input . --name belgif-validator-rest --main-jar belgif-rest-guide-validator-cli-latest.jar --type msi --app-version 2.2.0 --description "Validate OpenApi to Belgif guidelines" --vendor "Belgif" --icon ../package/belgif.ico --win-console --resource-dir "../package/windows" --runtime-image custom-jre --install-dir belgif-rest-guide-validator --file-associations ..\package\file-associations\FAyaml.properties --file-associations ..\package\file-associations\FAjson.properties --add-launcher belgif-validate-openapi="../package/cli-launcher.properties" --win-per-user-install
```
```


**Native Quarkus compilation**

Prereq:
* download latest JDK21 version of Mandrel - https://github.com/graalvm/mandrel/releases
* unpack it
* add GRAALVM_HOME=<directory>\mandrel-java21-<xxx>-Final env variable
* Add C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build to your PATH
* download and install Visual Studio community edition with these install options: https://www.graalvm.org/latest/getting-started/windows/#install-visual-studio-build-tools-and-windows-sdk
82 changes: 42 additions & 40 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,25 @@
<packaging>jar</packaging>

<properties>
<picocli.version>4.7.6</picocli.version>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>

<dependencies>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>${picocli.version}</version>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-picocli</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jaxb</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-quarkus</artifactId>
</dependency>
<dependency>
<groupId>io.github.belgif.rest.guide.validator</groupId>
Expand All @@ -33,8 +43,8 @@
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Expand All @@ -47,6 +57,18 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
Expand All @@ -63,41 +85,21 @@
<useDefaultDelimiters>true</useDefaultDelimiters>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/libs
</outputDirectory>
<includeScope>compile</includeScope>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs</classpathPrefix>
<mainClass>io.github.belgif.rest.guide.validator.cli.BelgifRestGuideValidator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<quarkus.native.enabled>true</quarkus.native.enabled>
<quarkus.package.jar.enabled>false</quarkus.package.jar.enabled>
</properties>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.github.belgif.rest.guide.validator.cli.util.VersionProvider;
import io.github.belgif.rest.guide.validator.runner.ValidationRunner;
import io.github.belgif.rest.guide.validator.runner.output.OutputType;
import io.quarkus.picocli.runtime.annotations.TopCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;
Expand All @@ -14,7 +15,7 @@
import java.util.Scanner;
import java.util.concurrent.Callable;


@TopCommand //annotation shouldn't be required according to doc, but cannot start quarkus-run else
@CommandLine.Command(name = "belgif-validate-openapi",
description = "Validate if an OpenAPI document conforms to the guidelines in the Belgif REST guide.",
footerHeading = "For additional information: ",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.belgif.rest.guide.validator.cli.config;

import io.github.belgif.rest.guide.validator.runner.output.junit.Error;
import io.github.belgif.rest.guide.validator.runner.output.junit.Failure;
import io.github.belgif.rest.guide.validator.runner.output.junit.Testcase;
import io.github.belgif.rest.guide.validator.runner.output.junit.Testsuite;
import io.github.belgif.rest.guide.validator.runner.output.model.OutputViolationReport;
import io.github.belgif.rest.guide.validator.runner.output.model.ViolationEntry;
import io.github.belgif.rest.guide.validator.runner.output.model.ViolationGroup;
import io.quarkus.runtime.annotations.RegisterForReflection;

/**
* Reflection config for Jackson/JAXB serialization - https://quarkus.io/guides/writing-native-applications-tips#registering-for-reflection.
* We could also add this annotation to each of the specific classes
*/
@RegisterForReflection(targets ={
OutputViolationReport.class, ViolationGroup.class, ViolationEntry.class, // for JSON output
Testsuite.class, Testcase.class, Failure.class, Error.class // for JUNIT output - JAXB - properties with classes not included will be ignored silently
})
public class ReflectionConfig {
}
1 change: 1 addition & 0 deletions cli/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
quarkus.arc.unremovable-types=org.drools.project.model.ProjectRuntime,org.kie.api.runtime.KieRuntimeBuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.github.belgif.rest.guide.validator.rules.oas;

import org.eclipse.microprofile.openapi.models.OpenAPI;
import io.github.belgif.rest.guide.validator.core.ApiFunctions;
import static io.github.belgif.rest.guide.validator.core.ApiFunctions.isMediaTypeIncluded;
import io.github.belgif.rest.guide.validator.core.ViolationReport;
import org.eclipse.microprofile.openapi.models.Operation;
import org.eclipse.microprofile.openapi.models.parameters.RequestBody;
import org.eclipse.microprofile.openapi.models.Paths;
import org.eclipse.microprofile.openapi.models.media.Content;
import org.eclipse.microprofile.openapi.models.media.MediaType;
import org.eclipse.microprofile.openapi.models.media.Schema;
import org.eclipse.microprofile.openapi.models.media.Schema.SchemaType;
import org.eclipse.microprofile.openapi.models.responses.APIResponses;
import org.eclipse.microprofile.openapi.models.responses.APIResponse;
import java.util.List
import java.util.Set;
import java.util.Map.Entry;
import io.github.belgif.rest.guide.validator.core.model.MediaTypeDefinition;

global io.github.belgif.rest.guide.validator.core.ViolationReport oas;


function void violationJsonRequestOrResponseHasNoSchema(ViolationReport oas, MediaTypeDefinition mediaTypeDefinition){
oas.addViolation("[evo-object]",
"In a request or response body, if any, you MUST always return a JSON object (and not e.g. an array) as a top level data structure to support future extensibility.",
mediaTypeDefinition);
}

rule "Application/Json should always have a schema (OAS3)"
when
$mediaTypeDefinition : MediaTypeDefinition(/model[schema == null])
eval(isMediaTypeIncluded($mediaTypeDefinition.getIdentifier(), Set.of("application/json")))
then
violationJsonRequestOrResponseHasNoSchema(oas, $mediaTypeDefinition);
end

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.belgif.rest.guide.validator.rules.oas;

import org.eclipse.microprofile.openapi.models.OpenAPI;
import io.github.belgif.rest.guide.validator.core.ApiFunctions
import io.github.belgif.rest.guide.validator.core.ViolationReport;
global io.github.belgif.rest.guide.validator.core.ViolationReport oas;
import org.eclipse.microprofile.openapi.models.media.Schema;
import org.eclipse.microprofile.openapi.models.media.Schema.SchemaType;
import io.github.belgif.rest.guide.validator.core.model.SchemaDefinition;
import java.util.Set;

function Set excludeCodes() {
return Set.of("BelgianRegionCode");
}

function void violationCodesShouldBeLowerCamelCase(ViolationReport oas, SchemaDefinition schema){
oas.addViolation("[cod-design]",
"New code types SHOULD be represented as string values in lowerCamelCase.", schema);
}

rule "Codes should io lowerCamelCase"
when
$schema: SchemaDefinition($schemaType: /model/type)
SchemaType( equals(SchemaType.STRING) ) from $schemaType
Schema( enumeration != null ) from $schema.getModel()
eval(((!$schema.getEffectiveIdentifier().contains("sort") && !$schema.getEffectiveIdentifier().contains("Sort")) && !ApiFunctions.isLowerCamelCase($schema.getModel().getEnumeration()))
|| (( $schema.getEffectiveIdentifier().contains("sort") || $schema.getEffectiveIdentifier().contains("Sort")) && !ApiFunctions.isLowerCamelCase($schema.getModel().getEnumeration(), "-")))
eval( ApiFunctions.isNotInSet($schema.getIdentifier(), excludeCodes()) )
then
violationCodesShouldBeLowerCamelCase(oas, $schema);
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.belgif.rest.guide.validator.rules.oas;

import org.eclipse.microprofile.openapi.models.OpenAPI;
import io.github.belgif.rest.guide.validator.core.ApiFunctions
import io.github.belgif.rest.guide.validator.core.ViolationReport;
global io.github.belgif.rest.guide.validator.core.ViolationReport oas;
import io.github.belgif.rest.guide.validator.core.model.OpenApiDefinition;
import io.github.belgif.rest.guide.validator.core.model.PathDefinition;
import io.github.belgif.rest.guide.validator.core.model.ServerDefinition;


function void violationComponentNamesShouldBeUpperCamelCase(ViolationReport oas, OpenApiDefinition component){
oas.addViolation("[oas-comp]",
"Component names SHOULD use UpperCamelCase notation. For abbreviations as well, all letters except the first one should be lowercased.", component);
}

rule "Component names should io UpperCamelCase"
when
$component: OpenApiDefinition(definitionType == DefinitionType.TOP_LEVEL, $jsonPointer: jsonPointer.toPrettyString(), $componentName: identifier)
String( startsWith("/components") ) from $jsonPointer
eval( !ApiFunctions.isUpperCamelCase($componentName) )
then
violationComponentNamesShouldBeUpperCamelCase(oas, $component);
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.belgif.rest.guide.validator.rules.oas;

import io.github.belgif.rest.guide.validator.core.ApiFunctions;
import io.github.belgif.rest.guide.validator.core.ViolationReport
import org.eclipse.microprofile.openapi.models.PathItem.HttpMethod;
import io.github.belgif.rest.guide.validator.core.model.OperationDefinition;
global io.github.belgif.rest.guide.validator.core.ViolationReport oas;
import io.github.belgif.rest.guide.validator.core.model.ResponseDefinition;
global io.github.belgif.rest.guide.validator.core.parser.Parser.ParserResult parserResult;

function void violationNoDefaultResponse(ViolationReport oas, OperationDefinition operation){
oas.addViolation("[prb-defaul]",
"A default Problem response SHOULD be added to each operation with media type \"application/problem+json\"",
"[Operation: " + operation.getIdentifier() + "]",
operation);
}

rule "Default Response is missing"
when
$operationDefinition: OperationDefinition(method != HttpMethod.HEAD && method != HttpMethod.OPTIONS)
OperationDefinition(/model/responses[defaultValue == null]) from $operationDefinition
then
violationNoDefaultResponse(oas, $operationDefinition);
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.github.belgif.rest.guide.validator.rules.oas;

import org.eclipse.microprofile.openapi.models.PathItem.HttpMethod;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import io.github.belgif.rest.guide.validator.core.ApiFunctions;
import io.github.belgif.rest.guide.validator.core.ViolationReport;
import io.github.belgif.rest.guide.validator.core.model.OperationDefinition;
import org.eclipse.microprofile.openapi.models.Operation;
import org.eclipse.microprofile.openapi.models.responses.APIResponses;
import org.eclipse.microprofile.openapi.models.responses.APIResponse;
import java.util.Set;

global io.github.belgif.rest.guide.validator.core.ViolationReport oas;

function void violationDelete(ViolationReport oas, OperationDefinition operation, String code){
oas.addViolation("[stat-codes]", "DELETE operation should not have this status code " , "[statuscode: " + code + "]",
operation);
}

rule "Delete Status Code 201 v2"
when
$operation: OperationDefinition( method == HttpMethod.DELETE )
OperationDefinition($response: /model/responses/APIResponses[keySet contains "201"]) from $operation
then
violationDelete(oas, $operation, "201");
end
rule "Delete Status Code 202 v2"
when
$operation: OperationDefinition( method == HttpMethod.DELETE )
OperationDefinition($response: /model/responses/APIResponses[keySet contains "202"]) from $operation
then
violationDelete(oas, $operation, "202");
end
rule "Delete Status Code 304 v2"
when
$operation: OperationDefinition( method == HttpMethod.DELETE )
OperationDefinition($response: /model/responses/APIResponses[keySet contains "304"]) from $operation
then
violationDelete(oas, $operation, "304");
end
rule "Delete Status Code 413 v2"
when
$operation: OperationDefinition( method == HttpMethod.DELETE )
OperationDefinition($response: /model/responses/APIResponses[keySet contains "413"]) from $operation
then
violationDelete(oas, $operation, "413");
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.belgif.rest.guide.validator.rules.oas;

import org.eclipse.microprofile.openapi.models.OpenAPI;
import io.github.belgif.rest.guide.validator.core.util.SchemaValidator;
import io.github.belgif.rest.guide.validator.core.ViolationReport;
global io.github.belgif.rest.guide.validator.core.ViolationReport oas;
import org.eclipse.microprofile.openapi.models.media.Schema;
import org.eclipse.microprofile.openapi.models.media.Schema.SchemaType;
import io.github.belgif.rest.guide.validator.core.model.SchemaDefinition;
import java.util.Map;

function void violationEnumValuesShouldValidateAgainstSchema(ViolationReport oas, SchemaDefinition schema, Map.Entry violation){
oas.addViolation("[oas-enum]",
"Enum value is not valid against the schema in which it is defined.", "[" + violation.getKey() + "] " + violation.getValue(), schema);
}

rule "Enum values should validate against schema"
when
$schema: SchemaDefinition($schemaType: /model/type)
Schema(enumeration != null) from $schema.getModel()
$violation: Map.Entry() from SchemaValidator.getEnumViolations($schema)
then
violationEnumValuesShouldValidateAgainstSchema(oas, $schema, $violation);
end
Loading
Loading