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
11 changes: 0 additions & 11 deletions src/main/java/com/redhat/exhort/integration/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,6 @@ private Constants() {}
public static final String DEFAULT_ACCEPT_MEDIA_TYPE = MediaType.APPLICATION_JSON;
public static final boolean DEFAULT_VERBOSE_MODE = false;

public static final List<String> PKG_MANAGERS =
Collections.unmodifiableList(
new ArrayList<>() {
{
add(MAVEN_PKG_MANAGER);
add(NPM_PKG_MANAGER);
add(PYPI_PKG_MANAGER);
add(GOLANG_PKG_MANAGER);
}
});

public static final List<String> PROVIDERS =
Collections.unmodifiableList(
new ArrayList<>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class ExhortIntegration extends EndpointRouteBuilder {

@Override
public void configure() {

// fmt:off
getContext().getRegistry().bind(MicrometerConstants.METRICS_REGISTRY_NAME, registry);
getContext().addRoutePolicyFactory(new MicrometerRoutePolicyFactory());
Expand All @@ -78,7 +79,8 @@ public void configure() {
.clientRequestValidation(true);

errorHandler(deadLetterChannel("direct:processInternalError"));

onException(Exception.class)
.log("foo?level=ERROR");
onException(IllegalArgumentException.class)
.routeId("onExhortIllegalArgumentException")
.useOriginalMessage()
Expand Down Expand Up @@ -182,8 +184,7 @@ public void configure() {
.to(seda("processFailedRequests"))
.setBody().simple("${exception.message}")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Status.INTERNAL_SERVER_ERROR.getStatusCode()))
.setHeader(Exchange.CONTENT_TYPE, constant(MediaType.TEXT_PLAIN))
;
.setHeader(Exchange.CONTENT_TYPE, constant(MediaType.TEXT_PLAIN));
//fmt:on
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,14 @@
package com.redhat.exhort.integration.backend.sbom;

import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;

import com.redhat.exhort.integration.Constants;
import com.redhat.exhort.model.DependencyTree;

public abstract class SbomParser {

public DependencyTree parse(InputStream input) {
var tree = buildTree(input);
validate(tree);
return tree;
return buildTree(input);
}

protected abstract DependencyTree buildTree(InputStream input);

protected void validate(DependencyTree tree) {
Set<String> types = new HashSet<>();
tree.dependencies()
.values()
.forEach(
d -> {
types.add(d.ref().purl().getType());
d.transitive().forEach(t -> types.add(t.purl().getType()));
});

var invalidTypes =
types.stream().filter(Predicate.not(Constants.PKG_MANAGERS::contains)).toList();
if (!invalidTypes.isEmpty()) {
throw new IllegalArgumentException("Unsupported package types received: " + invalidTypes);
}
if (types.size() > 1) {
throw new IllegalArgumentException(
"It is not supported to submit mixed Package Manager types. Found: " + types);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.camel.Body;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangeProperty;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.http.base.HttpOperationFailedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -89,23 +90,26 @@ public void processResponseError(Exchange exchange) {
ProviderStatus status = new ProviderStatus().ok(false).name(getProviderName());
Exception exception = (Exception) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
Throwable cause = exception.getCause();
if (cause != null) {
if (cause instanceof HttpOperationFailedException) {
HttpOperationFailedException httpException = (HttpOperationFailedException) cause;
String message = prettifyHttpError(httpException);
status.message(message).code(httpException.getStatusCode());
LOGGER.warn("Unable to process request: {}", message, cause);
} else {
status
.message(cause.getMessage())
.code(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
LOGGER.warn("Unable to process request to: {}", getProviderName(), cause);
}

while (cause instanceof RuntimeCamelException && cause != null) {
cause = cause.getCause();
}
if (cause == null) {
cause = exception;
}
if (cause instanceof HttpOperationFailedException) {
HttpOperationFailedException httpException = (HttpOperationFailedException) cause;
String message = prettifyHttpError(httpException);
status.message(message).code(httpException.getStatusCode());
LOGGER.warn("Unable to process request: {}", message, cause);
} else if (cause instanceof IllegalArgumentException) {
status.message(cause.getMessage()).code(422);
LOGGER.warn("Unable to process request to: {}", getProviderName(), exception);
} else {
status
.message(exception.getMessage())
.message(cause.getMessage())
.code(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
LOGGER.warn("Unable to process request to: {}", getProviderName(), exception);
LOGGER.warn("Unable to process request to: {}", getProviderName(), cause);
}
ProviderReport report = new ProviderReport().status(status).sources(Collections.emptyMap());
monitoringProcessor.processProviderError(exchange, exception, getProviderName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
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;
Expand Down Expand Up @@ -59,15 +60,16 @@ public void configure() {
.choice()
.when(method(OssIndexRequestBuilder.class, "isEmpty"))
.setBody(method(OssIndexResponseHandler.class, "emptyResponse"))
.transform().method(OssIndexResponseHandler.class, "buildReport")
.endChoice()
.otherwise()
.to(direct("ossSplitReq"))
.end()
.transform().method(OssIndexResponseHandler.class, "buildReport");
.to(direct("ossSplitReq"));

from(direct("ossSplitReq"))
.routeId("ossSplitReq")
.doTry()
.split(body(), AggregationStrategies.bean(OssIndexResponseHandler.class, "aggregateSplit"))
.stopOnException()
.parallelProcessing()
.transform().method(OssIndexRequestBuilder.class, "buildRequest")
.process(this::processComponentRequest)
Expand All @@ -78,8 +80,11 @@ public void configure() {
.end()
.to(vertxHttp("{{api.ossindex.host}}"))
.transform(method(OssIndexResponseHandler.class, "responseToIssues"))
.onFallback()
.process(responseHandler::processResponseError);
.end()
.transform().method(OssIndexResponseHandler.class, "buildReport")
.endDoTry()
.doCatch(HttpOperationFailedException.class)
.process(responseHandler::processResponseError);

from(direct("ossValidateCredentials"))
.routeId("ossValidateCredentials")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,37 +52,38 @@ public void configure() {

// fmt:off
from(direct("snykDepGraph"))
.routeId("snykDepGraph")
.process(this::setAuthToken)
.routeId("snykDepGraph")
.process(this::setAuthToken)
.circuitBreaker()
.faultToleranceConfiguration()
.timeoutEnabled(true)
.timeoutDuration(timeout)
.end()
.process(SnykRequestBuilder::validate)
.transform().method(SnykRequestBuilder.class, "fromDiGraph")
.process(this::processDepGraphRequest)
.circuitBreaker()
.faultToleranceConfiguration()
.timeoutEnabled(true)
.timeoutDuration(timeout)
.end()
.to(direct("snykRequest"))
.onFallback()
.process(responseHandler::processResponseError);
.onFallback()
.process(responseHandler::processResponseError);

from(direct("snykRequest"))
.routeId("snykRequest")
.to(vertxHttp("{{api.snyk.host}}"))
.transform().method(SnykResponseHandler.class, "responseToIssues")
.transform().method(SnykResponseHandler.class, "buildReport");
.routeId("snykRequest")
.to(vertxHttp("{{api.snyk.host}}"))
.transform().method(SnykResponseHandler.class, "responseToIssues")
.transform().method(SnykResponseHandler.class, "buildReport");

from(direct("snykValidateToken"))
.routeId("snykValidateToken")
.process(this::processTokenRequest)
.circuitBreaker()
.faultToleranceConfiguration()
.timeoutEnabled(true)
.timeoutDuration(timeout)
.end()
.to(vertxHttp("{{api.snyk.host}}"))
.setBody(constant("Token validated successfully"))
.onFallback()
.process(responseHandler::processTokenFallBack);
.routeId("snykValidateToken")
.process(this::processTokenRequest)
.circuitBreaker()
.faultToleranceConfiguration()
.timeoutEnabled(true)
.timeoutDuration(timeout)
.end()
.to(vertxHttp("{{api.snyk.host}}"))
.setBody(constant("Token validated successfully"))
.onFallback()
.process(responseHandler::processTokenFallBack);
// fmt:on
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@

package com.redhat.exhort.integration.providers.snyk;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

import org.apache.camel.Exchange;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
Expand All @@ -35,6 +41,17 @@
@RegisterForReflection
public class SnykRequestBuilder {

public static final List<String> SUPPORTED_PKG_MANAGERS =
Collections.unmodifiableList(
new ArrayList<>() {
{
add(Constants.MAVEN_PKG_MANAGER);
add(Constants.NPM_PKG_MANAGER);
add(Constants.PYPI_PKG_MANAGER);
add(Constants.GOLANG_PKG_MANAGER);
}
});

private ObjectMapper mapper = ObjectMapperProducer.newInstance();

public String fromDiGraph(DependencyTree req) throws JsonProcessingException {
Expand All @@ -50,6 +67,28 @@ public String fromDiGraph(DependencyTree req) throws JsonProcessingException {
return mapper.writeValueAsString(root);
}

public static void validate(Exchange exchange) {
var tree = exchange.getIn().getBody(DependencyTree.class);
Set<String> types = new HashSet<>();
tree.dependencies()
.values()
.forEach(
d -> {
types.add(d.ref().purl().getType());
d.transitive().forEach(t -> types.add(t.purl().getType()));
});

var invalidTypes =
types.stream().filter(Predicate.not(SUPPORTED_PKG_MANAGERS::contains)).toList();
if (!invalidTypes.isEmpty()) {
throw new IllegalArgumentException("Unsupported package types received: " + invalidTypes);
}
if (types.size() > 1) {
throw new IllegalArgumentException(
"It is not supported to submit mixed Package Manager types. Found: " + types);
}
}

private JsonNode addPackages(ObjectNode depGraph, DependencyTree tree, PackageRef root) {
var allDeps = tree.getAll();
var rootNode = createNode(root, allDeps);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import com.google.common.base.Charsets;
import com.redhat.exhort.extensions.InjectWireMock;
import com.redhat.exhort.extensions.WiremockV3Extension;
import com.redhat.exhort.integration.providers.snyk.SnykRequestBuilder;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
Expand Down Expand Up @@ -271,7 +272,7 @@ protected void stubSnykRequests() {
"{\"code\": 401, \"error\": \"Not authorised\""
+ ", \"message\": \"Not authorised\"}")));
// Other requests
Constants.PKG_MANAGERS.forEach(this::stubSnykEmptyRequest);
SnykRequestBuilder.SUPPORTED_PKG_MANAGERS.forEach(this::stubSnykEmptyRequest);
// Dependency request
server.stubFor(
post(Constants.SNYK_DEP_GRAPH_API_PATH)
Expand Down
Loading