diff --git a/src/main/java/com/redhat/exhort/integration/providers/ProviderResponseHandler.java b/src/main/java/com/redhat/exhort/integration/providers/ProviderResponseHandler.java index d64f1b09..2422e2da 100644 --- a/src/main/java/com/redhat/exhort/integration/providers/ProviderResponseHandler.java +++ b/src/main/java/com/redhat/exhort/integration/providers/ProviderResponseHandler.java @@ -48,6 +48,7 @@ import com.redhat.exhort.model.CvssScoreComparable.DependencyScoreComparator; import com.redhat.exhort.model.CvssScoreComparable.TransitiveScoreComparator; import com.redhat.exhort.model.DependencyTree; +import com.redhat.exhort.model.ProviderResponse; import com.redhat.exhort.monitoring.MonitoringProcessor; import io.quarkus.runtime.annotations.RegisterForReflection; @@ -66,7 +67,7 @@ public abstract class ProviderResponseHandler { protected abstract String getProviderName(); - public abstract Map> responseToIssues( + public abstract ProviderResponse responseToIssues( byte[] response, String privateProviders, DependencyTree tree) throws IOException; protected ProviderStatus defaultOkStatus(String provider) { @@ -111,9 +112,9 @@ public void processResponseError(Exchange exchange) { .code(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); LOGGER.warn("Unable to process request to: {}", getProviderName(), cause); } - ProviderReport report = new ProviderReport().status(status).sources(Collections.emptyMap()); + ProviderResponse response = new ProviderResponse(null, status); monitoringProcessor.processProviderError(exchange, exception, getProviderName()); - exchange.getMessage().setBody(report); + exchange.getMessage().setBody(response); } public void processTokenFallBack(Exchange exchange) { @@ -153,9 +154,9 @@ private static String prettifyHttpError(HttpOperationFailedException httpExcepti }; } - public Map> emptyResponse( + public ProviderResponse emptyResponse( @ExchangeProperty(Constants.DEPENDENCY_TREE_PROPERTY) DependencyTree tree) { - return Collections.emptyMap(); + return new ProviderResponse(Collections.emptyMap(), null); } private Map>> splitIssuesBySource( @@ -188,11 +189,14 @@ private Map>> splitIssuesBySource( } public ProviderReport buildReport( - @Body Map> issuesData, + @Body ProviderResponse response, @ExchangeProperty(Constants.DEPENDENCY_TREE_PROPERTY) DependencyTree tree, @ExchangeProperty(Constants.PROVIDER_PRIVATE_DATA_PROPERTY) String privateProviders) throws IOException { - var sourcesIssues = splitIssuesBySource(issuesData); + if (response.status() != null) { + return new ProviderReport().status(response.status()).sources(Collections.emptyMap()); + } + var sourcesIssues = splitIssuesBySource(response.issues()); Map reports = new HashMap<>(); sourcesIssues .keySet() diff --git a/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexIntegration.java b/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexIntegration.java index 933e619a..47e75d7e 100644 --- a/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexIntegration.java +++ b/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexIntegration.java @@ -25,7 +25,6 @@ import org.apache.camel.Exchange; import org.apache.camel.builder.AggregationStrategies; import org.apache.camel.builder.endpoint.EndpointRouteBuilder; -import org.apache.camel.http.base.HttpOperationFailedException; import org.eclipse.microprofile.config.inject.ConfigProperty; import com.redhat.exhort.integration.Constants; @@ -69,7 +68,6 @@ public void configure() { from(direct("ossSplitReq")) .routeId("ossSplitReq") - .doTry() .split(body(), AggregationStrategies.beanAllowNull(OssIndexResponseHandler.class, "aggregateSplit")) .parallelProcessing() .transform().method(OssIndexRequestBuilder.class, "buildRequest") @@ -81,10 +79,8 @@ public void configure() { .end() .to(vertxHttp("{{api.ossindex.host}}")) .transform(method(OssIndexResponseHandler.class, "responseToIssues")) - .end() - .endDoTry() - .doCatch(HttpOperationFailedException.class) - .process(responseHandler::processResponseError); + .onFallback() + .process(responseHandler::processResponseError); from(direct("ossValidateCredentials")) .routeId("ossValidateCredentials") diff --git a/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexResponseHandler.java b/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexResponseHandler.java index d8e34aaa..54f6e3e0 100644 --- a/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexResponseHandler.java +++ b/src/main/java/com/redhat/exhort/integration/providers/ossindex/OssIndexResponseHandler.java @@ -40,6 +40,7 @@ import com.redhat.exhort.integration.providers.ProviderResponseHandler; import com.redhat.exhort.model.CvssParser; import com.redhat.exhort.model.DependencyTree; +import com.redhat.exhort.model.ProviderResponse; import io.quarkus.runtime.annotations.RegisterForReflection; @@ -54,34 +55,37 @@ public class OssIndexResponseHandler extends ProviderResponseHandler { @Inject ObjectMapper mapper = ObjectMapperProducer.newInstance(); - public Map> aggregateSplit( - Map> oldExchange, Map> newExchange) + public ProviderResponse aggregateSplit(ProviderResponse oldExchange, ProviderResponse newExchange) throws IOException { if (oldExchange == null) { return newExchange; } + if (oldExchange.status() != null && !Boolean.TRUE.equals(oldExchange.status().getOk())) { + return oldExchange; + } oldExchange + .issues() .entrySet() .forEach( e -> { - var issues = newExchange.get(e.getKey()); + var issues = newExchange.issues().get(e.getKey()); if (issues != null) { e.getValue().addAll(issues); } }); - newExchange.keySet().stream() - .filter(k -> !oldExchange.keySet().contains(k)) + newExchange.issues().keySet().stream() + .filter(k -> !oldExchange.issues().keySet().contains(k)) .forEach( k -> { - oldExchange.put(k, newExchange.get(k)); + oldExchange.issues().put(k, newExchange.issues().get(k)); }); return oldExchange; } - public Map> responseToIssues( + public ProviderResponse responseToIssues( @Body byte[] response, String privateProviders, DependencyTree tree) throws IOException { var json = (ArrayNode) mapper.readTree(response); - return getIssues(json); + return new ProviderResponse(getIssues(json), null); } private Map> getIssues(ArrayNode response) { diff --git a/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykIntegration.java b/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykIntegration.java index 3edeb67d..30c572ba 100644 --- a/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykIntegration.java +++ b/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykIntegration.java @@ -64,13 +64,14 @@ public void configure() { .process(this::processDepGraphRequest) .to(direct("snykRequest")) .onFallback() - .process(responseHandler::processResponseError); + .process(responseHandler::processResponseError) + .end() + .transform().method(SnykResponseHandler.class, "buildReport"); from(direct("snykRequest")) .routeId("snykRequest") .to(vertxHttp("{{api.snyk.host}}")) - .transform().method(SnykResponseHandler.class, "responseToIssues") - .transform().method(SnykResponseHandler.class, "buildReport"); + .transform().method(SnykResponseHandler.class, "responseToIssues"); from(direct("snykValidateToken")) .routeId("snykValidateToken") diff --git a/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykResponseHandler.java b/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykResponseHandler.java index c80f8da3..f929381c 100644 --- a/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykResponseHandler.java +++ b/src/main/java/com/redhat/exhort/integration/providers/snyk/SnykResponseHandler.java @@ -41,6 +41,7 @@ import com.redhat.exhort.integration.providers.ProviderResponseHandler; import com.redhat.exhort.model.CvssParser; import com.redhat.exhort.model.DependencyTree; +import com.redhat.exhort.model.ProviderResponse; import io.quarkus.runtime.annotations.RegisterForReflection; @@ -56,7 +57,7 @@ public class SnykResponseHandler extends ProviderResponseHandler { "Sign up for a Snyk account to learn aboutn the vulnerabilities found"; @Inject ObjectMapper mapper = ObjectMapperProducer.newInstance(); - public Map> responseToIssues( + public ProviderResponse responseToIssues( @Body byte[] providerResponse, @ExchangeProperty(Constants.PROVIDER_PRIVATE_DATA_PROPERTY) String privateProviders, @ExchangeProperty(Constants.DEPENDENCY_TREE_PROPERTY) DependencyTree tree) @@ -64,7 +65,7 @@ public Map> responseToIssues( var filterUnique = privateProviders != null && privateProviders.contains(SNYK_PROVIDER); var snykResponse = mapper.readTree((byte[]) providerResponse); - return getIssues(snykResponse, filterUnique, tree); + return new ProviderResponse(getIssues(snykResponse, filterUnique, tree), null); } private Map> getIssues( diff --git a/src/main/java/com/redhat/exhort/model/ProviderResponse.java b/src/main/java/com/redhat/exhort/model/ProviderResponse.java new file mode 100644 index 00000000..c1001f08 --- /dev/null +++ b/src/main/java/com/redhat/exhort/model/ProviderResponse.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.redhat.exhort.model; + +import java.util.List; +import java.util.Map; + +import com.redhat.exhort.api.v4.Issue; +import com.redhat.exhort.api.v4.ProviderStatus; + +public record ProviderResponse(Map> issues, ProviderStatus status) {} diff --git a/src/test/java/com/redhat/exhort/integration/providers/ProviderResponseHandlerTest.java b/src/test/java/com/redhat/exhort/integration/providers/ProviderResponseHandlerTest.java index e614be60..8d246ef1 100644 --- a/src/test/java/com/redhat/exhort/integration/providers/ProviderResponseHandlerTest.java +++ b/src/test/java/com/redhat/exhort/integration/providers/ProviderResponseHandlerTest.java @@ -44,6 +44,7 @@ import com.redhat.exhort.integration.Constants; import com.redhat.exhort.model.DependencyTree; import com.redhat.exhort.model.DirectDependency; +import com.redhat.exhort.model.ProviderResponse; import jakarta.ws.rs.core.Response; @@ -59,7 +60,8 @@ public void testSummary( throws IOException { ProviderResponseHandler handler = new TestResponseHandler(); - ProviderReport response = handler.buildReport(issuesData, tree, null); + ProviderReport response = + handler.buildReport(new ProviderResponse(issuesData, null), tree, null); assertOkStatus(response); SourceSummary summary = getValidSource(response).getSummary(); @@ -108,7 +110,7 @@ public void testFilterDepsWithoutIssues() throws IOException { Map> issues = Map.of("pkg:npm/aa@1", List.of(buildIssue(1, 5f))); ProviderResponseHandler handler = new TestResponseHandler(); DependencyTree tree = buildTree(); - ProviderReport response = handler.buildReport(issues, tree, null); + ProviderReport response = handler.buildReport(new ProviderResponse(issues, null), tree, null); assertOkStatus(response); assertEquals(1, response.getSources().size()); Source report = response.getSources().get(TEST_SOURCE); @@ -127,7 +129,8 @@ public void testFilterTransitiveWithoutIssues() throws IOException { "pkg:npm/aba@1", List.of(buildIssue(3, 8f))); ProviderResponseHandler handler = new TestResponseHandler(); - ProviderReport response = handler.buildReport(issues, buildTree(), null); + ProviderReport response = + handler.buildReport(new ProviderResponse(issues, null), buildTree(), null); assertOkStatus(response); @@ -178,7 +181,8 @@ public void testSorted() throws IOException { "pkg:npm/abc@1", List.of(buildIssue(7, 6f))); ProviderResponseHandler handler = new TestResponseHandler(); - ProviderReport response = handler.buildReport(issues, buildTree(), null); + ProviderReport response = + handler.buildReport(new ProviderResponse(issues, null), buildTree(), null); assertOkStatus(response); DependencyReport reportHighest = getValidSource(response).getDependencies().get(0); @@ -347,7 +351,7 @@ protected String getProviderName() { } @Override - public Map> responseToIssues( + public ProviderResponse responseToIssues( byte[] response, String privateProviders, DependencyTree tree) throws IOException { throw new IllegalArgumentException("not implemented"); }