diff --git a/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java b/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java index 1d3e922a..41800da9 100644 --- a/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java +++ b/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java @@ -9,6 +9,7 @@ import com.getyourguide.openapi.validation.api.model.OpenApiViolation; import com.getyourguide.openapi.validation.api.model.RequestMetaData; import com.getyourguide.openapi.validation.api.model.ResponseMetaData; +import com.getyourguide.openapi.validation.core.exclusions.InternalViolationExclusions; import com.getyourguide.openapi.validation.core.mapper.ValidationReportToOpenApiViolationsMapper; import com.getyourguide.openapi.validation.core.validator.OpenApiInteractionValidatorWrapper; import java.net.URLDecoder; @@ -25,17 +26,20 @@ public class OpenApiRequestValidator { private final Executor executor; private final OpenApiInteractionValidatorWrapper validator; private final ValidationReportToOpenApiViolationsMapper mapper; + private final InternalViolationExclusions violationExclusions; public OpenApiRequestValidator( Executor executor, MetricsReporter metricsReporter, OpenApiInteractionValidatorWrapper validator, ValidationReportToOpenApiViolationsMapper mapper, + InternalViolationExclusions violationExclusions, OpenApiRequestValidationConfiguration configuration ) { this.executor = executor; this.validator = validator; this.mapper = mapper; + this.violationExclusions = violationExclusions; metricsReporter.reportStartup( validator != null, @@ -92,7 +96,10 @@ public List validateRequestObject( try { var simpleRequest = buildSimpleRequest(request, requestBody); var result = validator.validateRequest(simpleRequest); - return mapper.map(result, request, response, Direction.REQUEST, requestBody); + var violations = mapper.map(result, request, response, Direction.REQUEST, requestBody); + return violations.stream() + .filter(violation -> !violationExclusions.isExcluded(violation)) + .toList(); } catch (Exception e) { log.error("[OpenAPI Validation] Could not validate request", e); return List.of(); @@ -136,7 +143,10 @@ public List validateResponseObject( Request.Method.valueOf(request.getMethod().toUpperCase()), responseBuilder.build() ); - return mapper.map(result, request, response, Direction.RESPONSE, responseBody); + var violations = mapper.map(result, request, response, Direction.RESPONSE, responseBody); + return violations.stream() + .filter(violation -> !violationExclusions.isExcluded(violation)) + .toList(); } catch (Exception e) { log.error("[OpenAPI Validation] Could not validate response", e); return List.of(); diff --git a/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/log/ExclusionsOpenApiViolationHandler.java b/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/log/ExclusionsOpenApiViolationHandler.java deleted file mode 100644 index 6a73609b..00000000 --- a/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/log/ExclusionsOpenApiViolationHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.getyourguide.openapi.validation.core.log; - -import com.getyourguide.openapi.validation.api.log.OpenApiViolationHandler; -import com.getyourguide.openapi.validation.api.model.OpenApiViolation; -import com.getyourguide.openapi.validation.core.exclusions.InternalViolationExclusions; -import lombok.AllArgsConstructor; - -@AllArgsConstructor -public class ExclusionsOpenApiViolationHandler implements OpenApiViolationHandler { - private final OpenApiViolationHandler delegate; - private final InternalViolationExclusions violationExclusions; - - @Override - public void onOpenApiViolation(OpenApiViolation violation) { - if (violationExclusions.isExcluded(violation)) { - return; - } - - delegate.onOpenApiViolation(violation); - } -} diff --git a/openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java b/openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java index 9cb2c386..9b2e4882 100644 --- a/openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java +++ b/openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java @@ -7,8 +7,10 @@ import static org.mockito.Mockito.when; import com.atlassian.oai.validator.model.SimpleRequest; -import com.getyourguide.openapi.validation.api.metrics.MetricsReporter; +import com.atlassian.oai.validator.report.ValidationReport; +import com.getyourguide.openapi.validation.api.model.OpenApiViolation; import com.getyourguide.openapi.validation.api.model.RequestMetaData; +import com.getyourguide.openapi.validation.core.exclusions.InternalViolationExclusions; import com.getyourguide.openapi.validation.core.mapper.ValidationReportToOpenApiViolationsMapper; import com.getyourguide.openapi.validation.core.validator.OpenApiInteractionValidatorWrapper; import java.net.URI; @@ -25,22 +27,25 @@ public class OpenApiRequestValidatorTest { private Executor executor; private OpenApiInteractionValidatorWrapper validator; + private ValidationReportToOpenApiViolationsMapper mapper; private OpenApiRequestValidator openApiRequestValidator; + private InternalViolationExclusions internalViolationExclusions; @BeforeEach public void setup() { executor = mock(); validator = mock(); - MetricsReporter metricsReporter = mock(); - var mapper = mock(ValidationReportToOpenApiViolationsMapper.class); + mapper = mock(ValidationReportToOpenApiViolationsMapper.class); when(mapper.map(any(), any(), any(), any(), any())).thenReturn(List.of()); + internalViolationExclusions = mock(); openApiRequestValidator = new OpenApiRequestValidator( executor, - metricsReporter, + mock(), validator, mapper, + internalViolationExclusions, mock() ); } @@ -66,6 +71,23 @@ public void testWhenEncodedQueryParamIsPassedThenValidationShouldHappenWithQuery verifyQueryParamValueEquals(simpleRequestArgumentCaptor, "spaces", "this is a sparta"); } + @Test + public void testWhenViolationIsExcludedThenItShouldNotBeReturned() { + var uri = URI.create("https://api.example.com/path"); + var request = new RequestMetaData("GET", uri, new HashMap<>()); + var validationReport = mock(ValidationReport.class); + when(validator.validateRequest(any())).thenReturn(validationReport); + var violationExcluded = mock(OpenApiViolation.class); + var violations = List.of(violationExcluded, mock(OpenApiViolation.class)); + when(mapper.map(any(), any(), any(), any(), any())).thenReturn(violations); + when(internalViolationExclusions.isExcluded(violationExcluded)).thenReturn(true); + + var result = openApiRequestValidator.validateRequestObject(request, null); + + assertEquals(1, result.size()); + assertEquals(violations.get(1), result.getFirst()); + } + private void verifyQueryParamValueEquals( ArgumentCaptor simpleRequestArgumentCaptor, String name, diff --git a/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java b/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java index 130d8b94..f21da61f 100644 --- a/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java +++ b/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java @@ -21,7 +21,6 @@ import com.getyourguide.openapi.validation.core.exclusions.InternalViolationExclusions; import com.getyourguide.openapi.validation.core.executor.VirtualThreadLimitedExecutor; import com.getyourguide.openapi.validation.core.log.DefaultOpenApiViolationHandler; -import com.getyourguide.openapi.validation.core.log.ExclusionsOpenApiViolationHandler; import com.getyourguide.openapi.validation.core.log.ThrottlingOpenApiViolationHandler; import com.getyourguide.openapi.validation.core.mapper.ValidationReportToOpenApiViolationsMapper; import com.getyourguide.openapi.validation.core.metrics.DefaultMetricsReporter; @@ -70,11 +69,15 @@ public MetricsReporter metricsReporter( ); } + @Bean + public InternalViolationExclusions internalExclusions(Optional violationExclusions) { + return new InternalViolationExclusions(violationExclusions.orElseGet(NoViolationExclusions::new)); + } + @Bean public OpenApiViolationHandler openApiViolationHandler( ViolationLogger logger, - MetricsReporter metricsReporter, - Optional violationExclusions + MetricsReporter metricsReporter ) { OpenApiViolationHandler handler = new DefaultOpenApiViolationHandler(logger, metricsReporter); @@ -83,9 +86,6 @@ public OpenApiViolationHandler openApiViolationHandler( new ThrottlingOpenApiViolationHandler(handler, properties.getValidationReportThrottleWaitSeconds()); } - var exclusions = new InternalViolationExclusions(violationExclusions.orElseGet(NoViolationExclusions::new)); - handler = new ExclusionsOpenApiViolationHandler(handler, exclusions); - return handler; } @@ -104,7 +104,8 @@ public ValidatorConfiguration validatorConfiguration() { @Bean public OpenApiRequestValidator openApiRequestValidator( MetricsReporter metricsReporter, - ValidatorConfiguration validatorConfiguration + ValidatorConfiguration validatorConfiguration, + InternalViolationExclusions internalExclusions ) { var threadPoolExecutor = createThreadPoolExecutor(); @@ -114,6 +115,7 @@ public OpenApiRequestValidator openApiRequestValidator( new OpenApiInteractionValidatorFactory() .build(properties.getSpecificationFilePath(), validatorConfiguration), new ValidationReportToOpenApiViolationsMapper(), + internalExclusions, properties.toOpenApiRequestValidationConfiguration() ); }