diff --git a/repository-meta-analyzer/pom.xml b/repository-meta-analyzer/pom.xml
index b42a22ac6..755c7fcb7 100644
--- a/repository-meta-analyzer/pom.xml
+++ b/repository-meta-analyzer/pom.xml
@@ -82,6 +82,11 @@
quarkus-junit5
test
+
+ org.junit.platform
+ junit-platform-suite
+ test
+
io.quarkus
quarkus-junit5-mockito
diff --git a/repository-meta-analyzer/src/test/java/org/hyades/RepositoryMetaAnalyzerIT.java b/repository-meta-analyzer/src/test/java/org/hyades/RepositoryMetaAnalyzerIT.java
index b758d6b74..b3b08ea32 100644
--- a/repository-meta-analyzer/src/test/java/org/hyades/RepositoryMetaAnalyzerIT.java
+++ b/repository-meta-analyzer/src/test/java/org/hyades/RepositoryMetaAnalyzerIT.java
@@ -6,6 +6,8 @@
import com.github.tomakehurst.wiremock.http.ContentTypeHeader;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusIntegrationTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
import io.quarkus.test.kafka.InjectKafkaCompanion;
import io.quarkus.test.kafka.KafkaCompanionResource;
import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion;
@@ -22,6 +24,8 @@
import org.hyades.util.WireMockTestResource.InjectWireMock;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.platform.suite.api.SelectClasses;
+import org.junit.platform.suite.api.Suite;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -31,86 +35,264 @@
import static org.assertj.core.api.Assertions.assertThat;
-@QuarkusIntegrationTest
-@QuarkusTestResource(KafkaCompanionResource.class)
-@QuarkusTestResource(WireMockTestResource.class)
+@Suite
+@SelectClasses(value = {
+ RepositoryMetaAnalyzerIT.WithValidPurl.class,
+ RepositoryMetaAnalyzerIT.WithInvalidPurl.class,
+ RepositoryMetaAnalyzerIT.NoCapableAnalyzer.class,
+ RepositoryMetaAnalyzerIT.InternalAnalyzerNonInternalComponent.class
+})
class RepositoryMetaAnalyzerIT {
- @InjectKafkaCompanion
- KafkaCompanion kafkaCompanion;
-
- @InjectWireMock
- WireMockServer wireMockServer;
-
- @BeforeEach
- void beforeEach() throws Exception {
- // Workaround for the fact that Quarkus < 2.17.0 does not support initializing the database container
- // with data. We can't use EntityManager etc. because the test is executed against an already built
- // artifact (JAR, container, or native image).
- // Can be replaced with quarkus.datasource.devservices.init-script-path after upgrading to Quarkus 2.17.0:
- // https://github.com/quarkusio/quarkus/pull/30455
- try (final Connection connection = DriverManager.getConnection(
- ConfigProvider.getConfig().getValue("quarkus.datasource.jdbc.url", String.class),
- ConfigProvider.getConfig().getValue("quarkus.datasource.username", String.class),
- ConfigProvider.getConfig().getValue("quarkus.datasource.password", String.class))) {
- final PreparedStatement ps = connection.prepareStatement("""
- INSERT INTO "REPOSITORY" ("ENABLED", "IDENTIFIER", "INTERNAL", "PASSWORD", "RESOLUTION_ORDER", "TYPE", "URL", "AUTHENTICATIONREQUIRED")
- VALUES ('true', 'test', false, NULL, 1, 'GO_MODULES', 'http://localhost:%d', false);
- """.formatted(wireMockServer.port()));
- ps.execute();
- }
+ @QuarkusIntegrationTest
+ @QuarkusTestResource(KafkaCompanionResource.class)
+ @QuarkusTestResource(WireMockTestResource.class)
+ @TestProfile(WithValidPurl.TestProfile.class)
+ static class WithValidPurl {
+
+ public static class TestProfile implements QuarkusTestProfile {}
+
+ @InjectKafkaCompanion
+ KafkaCompanion kafkaCompanion;
- wireMockServer.stubFor(WireMock.get(WireMock.anyUrl())
- .willReturn(WireMock.aResponse()
- .withStatus(200)
- .withResponseBody(Body.ofBinaryOrText("""
- {
- "Version": "v6.6.6",
- "Time": "2022-09-28T21:59:32Z",
- "Origin": {
- "VCS": "git",
- "URL": "https://github.com/acme/acme-lib",
- "Ref": "refs/tags/v6.6.6",
- "Hash": "39a1d8f8f69040a53114e1ea481e48f6d792c05e"
+ @InjectWireMock
+ WireMockServer wireMockServer;
+
+ @BeforeEach
+ void beforeEach() throws Exception {
+ // Workaround for the fact that Quarkus < 2.17.0 does not support initializing the database container
+ // with data. We can't use EntityManager etc. because the test is executed against an already built
+ // artifact (JAR, container, or native image).
+ // Can be replaced with quarkus.datasource.devservices.init-script-path after upgrading to Quarkus 2.17.0:
+ // https://github.com/quarkusio/quarkus/pull/30455
+ try (final Connection connection = DriverManager.getConnection(
+ ConfigProvider.getConfig().getValue("quarkus.datasource.jdbc.url", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.username", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.password", String.class))) {
+ final PreparedStatement ps = connection.prepareStatement("""
+ INSERT INTO "REPOSITORY" ("ENABLED", "IDENTIFIER", "INTERNAL", "PASSWORD", "RESOLUTION_ORDER", "TYPE", "URL", "AUTHENTICATIONREQUIRED")
+ VALUES ('true', 'test', false, NULL, 1, 'GO_MODULES', 'http://localhost:%d', false);
+ """.formatted(wireMockServer.port()));
+ ps.execute();
+ }
+
+ wireMockServer.stubFor(WireMock.get(WireMock.anyUrl())
+ .willReturn(WireMock.aResponse()
+ .withStatus(200)
+ .withResponseBody(Body.ofBinaryOrText("""
+ {
+ "Version": "v6.6.6",
+ "Time": "2022-09-28T21:59:32Z",
+ "Origin": {
+ "VCS": "git",
+ "URL": "https://github.com/acme/acme-lib",
+ "Ref": "refs/tags/v6.6.6",
+ "Hash": "39a1d8f8f69040a53114e1ea481e48f6d792c05e"
+ }
}
- }
- """.getBytes(), new ContentTypeHeader(MediaType.APPLICATION_JSON))
- )));
+ """.getBytes(), new ContentTypeHeader(MediaType.APPLICATION_JSON))
+ )));
+ }
+
+ @Test
+ void test() {
+ final var command = AnalysisCommand.newBuilder()
+ .setComponent(org.hyades.proto.repometaanalysis.v1.Component.newBuilder()
+ .setPurl("pkg:golang/github.com/acme/acme-lib@9.1.1"))
+ .build();
+
+ kafkaCompanion
+ .produce(Serdes.String(), new KafkaProtobufSerde<>(AnalysisCommand.parser()))
+ .fromRecords(new ProducerRecord<>(KafkaTopic.REPO_META_ANALYSIS_COMMAND.getName(), "foo", command));
+
+ final List> results = kafkaCompanion
+ .consume(Serdes.String(), new KafkaProtobufSerde<>(AnalysisResult.parser()))
+ .fromTopics(KafkaTopic.REPO_META_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(5))
+ .awaitCompletion()
+ .getRecords();
+
+ assertThat(results).satisfiesExactly(
+ record -> {
+ assertThat(record.key()).isEqualTo("pkg:golang/github.com/acme/acme-lib");
+ assertThat(record.value()).isNotNull();
+ final AnalysisResult result = record.value();
+ assertThat(result.hasComponent()).isTrue();
+ assertThat(result.hasRepository()).isTrue();
+ assertThat(result.getRepository()).isEqualTo("test");
+ assertThat(result.hasLatestVersion()).isTrue();
+ assertThat(result.getLatestVersion()).isEqualTo("v6.6.6");
+ assertThat(result.hasPublished()).isTrue();
+ assertThat(result.getPublished().getSeconds()).isEqualTo(1664402372);
+ }
+ );
+ }
+ }
+
+ @QuarkusIntegrationTest
+ @QuarkusTestResource(KafkaCompanionResource.class)
+ @QuarkusTestResource(WireMockTestResource.class)
+ @TestProfile(WithInvalidPurl.TestProfile.class)
+ static class WithInvalidPurl {
+
+ public static class TestProfile implements QuarkusTestProfile {}
+
+ @InjectKafkaCompanion
+ KafkaCompanion kafkaCompanion;
+
+ @InjectWireMock
+ WireMockServer wireMockServer;
+
+ @BeforeEach
+ void beforeEach() throws Exception {
+ try (final Connection connection = DriverManager.getConnection(
+ ConfigProvider.getConfig().getValue("quarkus.datasource.jdbc.url", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.username", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.password", String.class))) {
+ final PreparedStatement ps = connection.prepareStatement("""
+ INSERT INTO "REPOSITORY" ("ENABLED", "IDENTIFIER", "INTERNAL", "PASSWORD", "RESOLUTION_ORDER", "TYPE", "URL", "AUTHENTICATIONREQUIRED")
+ VALUES ('true', 'test', false, NULL, 2, 'NPM', 'http://localhost:%d', false);
+ """.formatted(wireMockServer.port()));
+ ps.execute();
+ }
+ }
+
+ @Test
+ void test() {
+ final var command = AnalysisCommand.newBuilder()
+ .setComponent(org.hyades.proto.repometaanalysis.v1.Component.newBuilder()
+ .setPurl("invalid-purl"))
+ .build();
+
+ kafkaCompanion
+ .produce(Serdes.String(), new KafkaProtobufSerde<>(AnalysisCommand.parser()))
+ .fromRecords(new ProducerRecord<>(KafkaTopic.REPO_META_ANALYSIS_COMMAND.getName(), "foo", command));
+
+ final List> results = kafkaCompanion
+ .consume(Serdes.String(), new KafkaProtobufSerde<>(AnalysisResult.parser()))
+ .fromTopics(KafkaTopic.REPO_META_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(5))
+ .awaitCompletion()
+ .getRecords();
+
+ assertThat(results).isEmpty();
+ }
}
- @Test
- void test() {
- final var command = AnalysisCommand.newBuilder()
- .setComponent(org.hyades.proto.repometaanalysis.v1.Component.newBuilder()
- .setPurl("pkg:golang/github.com/acme/acme-lib@9.1.1"))
- .build();
-
- kafkaCompanion
- .produce(Serdes.String(), new KafkaProtobufSerde<>(AnalysisCommand.parser()))
- .fromRecords(new ProducerRecord<>(KafkaTopic.REPO_META_ANALYSIS_COMMAND.getName(), "foo", command));
-
- final List> results = kafkaCompanion
- .consume(Serdes.String(), new KafkaProtobufSerde<>(AnalysisResult.parser()))
- .fromTopics(KafkaTopic.REPO_META_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(5))
- .awaitCompletion()
- .getRecords();
-
- assertThat(results).satisfiesExactly(
- record -> {
- assertThat(record.key()).isEqualTo("pkg:golang/github.com/acme/acme-lib");
- assertThat(record.value()).isNotNull();
-
- final AnalysisResult result = record.value();
- assertThat(result.hasComponent()).isTrue();
- assertThat(result.getComponent()).isEqualTo(command.getComponent());
- assertThat(result.hasRepository()).isTrue();
- assertThat(result.getRepository()).isEqualTo("test");
- assertThat(result.hasLatestVersion()).isTrue();
- assertThat(result.getLatestVersion()).isEqualTo("v6.6.6");
- assertThat(result.hasPublished()).isTrue();
- assertThat(result.getPublished().getSeconds()).isEqualTo(1664402372);
- }
- );
+ @QuarkusIntegrationTest
+ @QuarkusTestResource(KafkaCompanionResource.class)
+ @QuarkusTestResource(WireMockTestResource.class)
+ @TestProfile(NoCapableAnalyzer.TestProfile.class)
+ static class NoCapableAnalyzer {
+
+ public static class TestProfile implements QuarkusTestProfile {}
+
+ @InjectKafkaCompanion
+ KafkaCompanion kafkaCompanion;
+
+ @InjectWireMock
+ WireMockServer wireMockServer;
+
+ @BeforeEach
+ void beforeEach() throws Exception {
+ try (final Connection connection = DriverManager.getConnection(
+ ConfigProvider.getConfig().getValue("quarkus.datasource.jdbc.url", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.username", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.password", String.class))) {
+ final PreparedStatement ps = connection.prepareStatement("""
+ INSERT INTO "REPOSITORY" ("ENABLED", "IDENTIFIER", "INTERNAL", "PASSWORD", "RESOLUTION_ORDER", "TYPE", "URL", "AUTHENTICATIONREQUIRED")
+ VALUES ('true', 'test', false, NULL, 2, 'CPAN', 'http://localhost:%d', false);
+ """.formatted(wireMockServer.port()));
+ ps.execute();
+ }
+ }
+
+ @Test
+ void test() {
+ final var command = AnalysisCommand.newBuilder()
+ .setComponent(org.hyades.proto.repometaanalysis.v1.Component.newBuilder()
+ .setPurl("pkg:github/github.com/acme/acme-lib@9.1.1"))
+ .build();
+
+ kafkaCompanion
+ .produce(Serdes.String(), new KafkaProtobufSerde<>(AnalysisCommand.parser()))
+ .fromRecords(new ProducerRecord<>(KafkaTopic.REPO_META_ANALYSIS_COMMAND.getName(), "foo", command));
+
+ final List> results = kafkaCompanion
+ .consume(Serdes.String(), new KafkaProtobufSerde<>(AnalysisResult.parser()))
+ .fromTopics(KafkaTopic.REPO_META_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(5))
+ .awaitCompletion()
+ .getRecords();
+ assertThat(results).satisfiesExactly(
+ record -> {
+ assertThat(record.key()).isEqualTo("pkg:github/github.com/acme/acme-lib");
+ assertThat(record.value()).isNotNull();
+ final AnalysisResult result = record.value();
+ assertThat(result.hasComponent()).isTrue();
+ assertThat(result.getComponent()).isEqualTo(command.getComponent());
+ assertThat(result.hasRepository()).isFalse();
+ assertThat(result.hasLatestVersion()).isFalse();
+ assertThat(result.hasPublished()).isFalse();
+ }
+ );
+ }
}
+ @QuarkusIntegrationTest
+ @QuarkusTestResource(KafkaCompanionResource.class)
+ @QuarkusTestResource(WireMockTestResource.class)
+ @TestProfile(InternalAnalyzerNonInternalComponent.TestProfile.class)
+ static class InternalAnalyzerNonInternalComponent {
+
+ public static class TestProfile implements QuarkusTestProfile {}
+
+ @InjectKafkaCompanion
+ KafkaCompanion kafkaCompanion;
+
+ @InjectWireMock
+ WireMockServer wireMockServer;
+
+ @BeforeEach
+ void beforeEach() throws Exception {
+ try (final Connection connection = DriverManager.getConnection(
+ ConfigProvider.getConfig().getValue("quarkus.datasource.jdbc.url", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.username", String.class),
+ ConfigProvider.getConfig().getValue("quarkus.datasource.password", String.class))) {
+ final PreparedStatement ps = connection.prepareStatement("""
+ INSERT INTO "REPOSITORY" ("ENABLED", "IDENTIFIER", "INTERNAL", "PASSWORD", "RESOLUTION_ORDER", "TYPE", "URL", "AUTHENTICATIONREQUIRED")
+ VALUES ('true', 'test', true, NULL, 2, 'MAVEN', 'http://localhost:%d', false);
+ """.formatted(wireMockServer.port()));
+ ps.execute();
+ }
+ }
+
+ @Test
+ void test() {
+ final var command = AnalysisCommand.newBuilder()
+ .setComponent(org.hyades.proto.repometaanalysis.v1.Component.newBuilder()
+ .setPurl("pkg:golang/github.com/acme/acme-lib@9.1.1")
+ .setInternal(false))
+ .build();
+
+ kafkaCompanion
+ .produce(Serdes.String(), new KafkaProtobufSerde<>(AnalysisCommand.parser()))
+ .fromRecords(new ProducerRecord<>(KafkaTopic.REPO_META_ANALYSIS_COMMAND.getName(), "foo", command));
+
+ final List> results = kafkaCompanion
+ .consume(Serdes.String(), new KafkaProtobufSerde<>(AnalysisResult.parser()))
+ .fromTopics(KafkaTopic.REPO_META_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(5))
+ .awaitCompletion()
+ .getRecords();
+ assertThat(results).satisfiesExactly(
+ record -> {
+ assertThat(record.key()).isEqualTo("pkg:golang/github.com/acme/acme-lib");
+ assertThat(record.value()).isNotNull();
+ final AnalysisResult result = record.value();
+ assertThat(result.hasComponent()).isTrue();
+ assertThat(result.getComponent()).isEqualTo(command.getComponent());
+ assertThat(result.hasRepository()).isFalse();
+ assertThat(result.hasLatestVersion()).isFalse();
+ assertThat(result.hasPublished()).isFalse();
+ }
+ );
+ }
+ }
}
diff --git a/vulnerability-analyzer/src/test/java/org/hyades/VulnerabilityAnalyzerIT.java b/vulnerability-analyzer/src/test/java/org/hyades/VulnerabilityAnalyzerIT.java
index 268491658..4ada5a4a6 100644
--- a/vulnerability-analyzer/src/test/java/org/hyades/VulnerabilityAnalyzerIT.java
+++ b/vulnerability-analyzer/src/test/java/org/hyades/VulnerabilityAnalyzerIT.java
@@ -1,5 +1,8 @@
package org.hyades;
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.http.Body;
+import com.github.tomakehurst.wiremock.http.ContentTypeHeader;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import io.quarkus.test.junit.QuarkusTestProfile;
@@ -7,8 +10,12 @@
import io.quarkus.test.kafka.InjectKafkaCompanion;
import io.quarkus.test.kafka.KafkaCompanionResource;
import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion;
+import jakarta.ws.rs.core.MediaType;
+import org.apache.http.HttpHeaders;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.producer.ProducerRecord;
+import org.cyclonedx.proto.v1_4.ScoreMethod;
+import org.cyclonedx.proto.v1_4.Severity;
import org.hyades.common.KafkaTopic;
import org.hyades.proto.KafkaProtobufSerde;
import org.hyades.proto.vulnanalysis.v1.Component;
@@ -17,71 +24,270 @@
import org.hyades.proto.vulnanalysis.v1.ScanResult;
import org.hyades.proto.vulnanalysis.v1.ScanStatus;
import org.hyades.proto.vulnanalysis.v1.Scanner;
+import org.hyades.util.WireMockTestResource;
import org.junit.jupiter.api.Test;
+import org.junit.platform.suite.api.SelectClasses;
+import org.junit.platform.suite.api.Suite;
+import java.io.IOException;
import java.time.Duration;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;
+import static org.apache.commons.io.IOUtils.resourceToByteArray;
import static org.assertj.core.api.Assertions.assertThat;
-@QuarkusIntegrationTest
-@QuarkusTestResource(KafkaCompanionResource.class)
-@TestProfile(VulnerabilityAnalyzerIT.TestProfile.class)
+@Suite
+@SelectClasses(value = {
+ VulnerabilityAnalyzerIT.ScannerInternal.class,
+ VulnerabilityAnalyzerIT.ScannerOssindex.class,
+ VulnerabilityAnalyzerIT.ScannerSnyk.class
+})
class VulnerabilityAnalyzerIT {
- public static class TestProfile implements QuarkusTestProfile {
+ @QuarkusIntegrationTest
+ @QuarkusTestResource(KafkaCompanionResource.class)
+ @TestProfile(ScannerInternal.TestProfile.class)
+ static class ScannerInternal {
+ public static class TestProfile implements QuarkusTestProfile {
- @Override
- public Map getConfigOverrides() {
- return Map.of(
- "scanner.internal.enabled", "true",
- "scanner.ossindex.enabled", "false",
- "scanner.snyk.enabled", "false",
- "quarkus.kafka.snappy.enabled", "true"
+ @Override
+ public Map getConfigOverrides() {
+ return Map.of(
+ "scanner.internal.enabled", "true",
+ "scanner.ossindex.enabled", "false",
+ "scanner.snyk.enabled", "false",
+ "quarkus.kafka.snappy.enabled", "true"
+ );
+ }
+ }
+
+ @InjectKafkaCompanion
+ KafkaCompanion kafkaCompanion;
+
+ @Test
+ void test() {
+ final var component = Component.newBuilder()
+ .setUuid(UUID.randomUUID().toString())
+ .setPurl("pkg:maven/org.yaml/snakeyaml@1.33")
+ .build();
+ final var scanCommand = ScanCommand.newBuilder()
+ .setComponent(component)
+ .build();
+ final var scanKey = ScanKey.newBuilder()
+ .setScanToken(UUID.randomUUID().toString())
+ .setComponentUuid(component.getUuid())
+ .build();
+
+ kafkaCompanion
+ .produce(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanCommand.parser()))
+ .fromRecords(new ProducerRecord<>(KafkaTopic.VULN_ANALYSIS_COMPONENT.getName(), scanKey, scanCommand));
+
+ final ConsumerRecord result = kafkaCompanion
+ .consume(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanResult.parser()))
+ .fromTopics(KafkaTopic.VULN_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(5))
+ .awaitCompletion()
+ .getFirstRecord();
+
+ assertThat(result.key()).isEqualTo(scanKey);
+ assertThat(result.value().getKey()).isEqualTo(scanKey);
+ assertThat(result.value().getScannerResultsList()).satisfiesExactly(
+ scannerResult -> {
+ assertThat(scannerResult.getStatus()).isEqualTo(ScanStatus.SCAN_STATUS_SUCCESSFUL);
+ assertThat(scannerResult.getScanner()).isEqualTo(Scanner.SCANNER_INTERNAL);
+ assertThat(scannerResult.getBom().getVulnerabilitiesCount()).isZero();
+ assertThat(scannerResult.hasFailureReason()).isFalse();
+ }
);
}
}
- @InjectKafkaCompanion
- KafkaCompanion kafkaCompanion;
-
- @Test
- void test() {
- final var component = Component.newBuilder()
- .setUuid(UUID.randomUUID().toString())
- .setCpe("cpe:/a:acme:application:9.1.1")
- .setPurl("pkg:maven/acme/a@9.1.1")
- .build();
- final var scanCommand = ScanCommand.newBuilder()
- .setComponent(component)
- .build();
- final var scanKey = ScanKey.newBuilder()
- .setScanToken(UUID.randomUUID().toString())
- .setComponentUuid(component.getUuid())
- .build();
-
- kafkaCompanion
- .produce(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanCommand.parser()))
- .fromRecords(new ProducerRecord<>(KafkaTopic.VULN_ANALYSIS_COMPONENT.getName(), scanKey, scanCommand));
-
- final ConsumerRecord result = kafkaCompanion
- .consume(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanResult.parser()))
- .fromTopics(KafkaTopic.VULN_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(5))
- .awaitCompletion()
- .getFirstRecord();
-
- assertThat(result.key()).isEqualTo(scanKey);
- assertThat(result.value().getKey()).isEqualTo(scanKey);
- assertThat(result.value().getScannerResultsList()).satisfiesExactly(
- scannerResult -> {
- assertThat(scannerResult.getStatus()).isEqualTo(ScanStatus.SCAN_STATUS_SUCCESSFUL);
- assertThat(scannerResult.getScanner()).isEqualTo(Scanner.SCANNER_INTERNAL);
- assertThat(scannerResult.getBom().getVulnerabilitiesCount()).isZero();
- assertThat(scannerResult.hasFailureReason()).isFalse();
- }
- );
+ @QuarkusIntegrationTest
+ @QuarkusTestResource(KafkaCompanionResource.class)
+ @TestProfile(ScannerOssindex.TestProfile.class)
+ static class ScannerOssindex {
+ public static class TestProfile implements QuarkusTestProfile {
+
+ @Override
+ public Map getConfigOverrides() {
+ return Map.of(
+ "scanner.internal.enabled", "false",
+ "scanner.ossindex.enabled", "true",
+ "scanner.snyk.enabled", "false",
+ "quarkus.kafka.snappy.enabled", "true",
+ "scanner.ossindex.batch-size", "1"
+ );
+ }
+
+ @Override
+ public List testResources() {
+ return List.of(
+ new TestResourceEntry(KafkaCompanionResource.class),
+ new TestResourceEntry(
+ WireMockTestResource.class,
+ Map.of("serverUrlProperty", "scanner.ossindex.api.baseurl")
+ ));
+ }
+ }
+
+ @InjectKafkaCompanion
+ KafkaCompanion kafkaCompanion;
+
+ @WireMockTestResource.InjectWireMock
+ WireMockServer wireMock;
+
+ @Test
+ void test() throws IOException {
+ final var component = Component.newBuilder()
+ .setUuid(UUID.randomUUID().toString())
+ .setPurl("pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1")
+ .build();
+ final var scanCommand = ScanCommand.newBuilder()
+ .setComponent(component)
+ .build();
+ final var scanKey = ScanKey.newBuilder()
+ .setScanToken(UUID.randomUUID().toString())
+ .setComponentUuid(component.getUuid())
+ .build();
+
+ wireMock.stubFor(post(urlPathMatching("/.*"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+ .withResponseBody(Body.ofBinaryOrText(resourceToByteArray("/ossindex/one-component-one-issue-response.json"), new ContentTypeHeader(MediaType.APPLICATION_OCTET_STREAM)))));
+
+ kafkaCompanion
+ .produce(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanCommand.parser()))
+ .fromRecords(new ProducerRecord<>(KafkaTopic.VULN_ANALYSIS_COMPONENT.getName(), scanKey, scanCommand));
+
+ final ConsumerRecord result = kafkaCompanion
+ .consume(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanResult.parser()))
+ .fromTopics(KafkaTopic.VULN_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(15))
+ .awaitCompletion()
+ .getFirstRecord();
+ assertThat(result.key()).isEqualTo(scanKey);
+ assertThat(result.value().getKey()).isEqualTo(scanKey);
+ assertThat(result.value().getScannerResultsList()).satisfiesExactly(
+ scannerResult -> {
+ assertThat(scannerResult.getStatus()).isEqualTo(ScanStatus.SCAN_STATUS_SUCCESSFUL);
+ assertThat(scannerResult.getScanner()).isEqualTo(Scanner.SCANNER_OSSINDEX);
+ assertThat(scannerResult.getBom().getVulnerabilitiesCount()).isEqualTo(1);
+ assertThat(scannerResult.hasFailureReason()).isFalse();
+ var vuln = scannerResult.getBom().getVulnerabilities(0);
+ assertThat(vuln.getId()).isEqualTo("CVE-2020-36518");
+ assertThat(vuln.getSource().getName()).isEqualTo("NVD");
+ assertThat(vuln.getDescription()).isEqualTo("[CVE-2020-36518] CWE-787: Out-of-bounds Write");
+ assertThat(vuln.getDetail()).startsWith("jackson-databind");
+ var rating = vuln.getRatings(0);
+ assertThat(rating.getSource().getName()).isEqualTo("OSSINDEX");
+ assertThat(rating.getScore()).isEqualTo(7.5);
+ assertThat(rating.getMethod()).isEqualTo(ScoreMethod.SCORE_METHOD_CVSSV3);
+ assertThat(rating.getVector()).isEqualTo("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H");
+ assertThat(rating.getSeverity()).isEqualTo(Severity.SEVERITY_HIGH);
+ assertThat(vuln.getCwes(0)).isEqualTo(787);
+ assertThat(vuln.getAdvisoriesCount()).isEqualTo(3);
+ }
+ );
+ }
}
+ @QuarkusIntegrationTest
+ @QuarkusTestResource(KafkaCompanionResource.class)
+ @TestProfile(ScannerSnyk.TestProfile.class)
+ static class ScannerSnyk {
+ public static class TestProfile implements QuarkusTestProfile {
+
+ @Override
+ public Map getConfigOverrides() {
+ return Map.of(
+ "scanner.internal.enabled", "false",
+ "scanner.ossindex.enabled", "false",
+ "scanner.snyk.enabled", "true",
+ "quarkus.kafka.snappy.enabled", "true",
+ "scanner.snyk.api.org-id", "org-id",
+ "scanner.snyk.api.tokens", "api-token",
+ "scanner.snyk.alias-sync-enabled", "true"
+ );
+ }
+
+ @Override
+ public List testResources() {
+ return List.of(
+ new TestResourceEntry(KafkaCompanionResource.class),
+ new TestResourceEntry(
+ WireMockTestResource.class,
+ Map.of("serverUrlProperty", "scanner.snyk.api.baseurl")
+ ));
+ }
+ }
+
+ @InjectKafkaCompanion
+ KafkaCompanion kafkaCompanion;
+
+ @WireMockTestResource.InjectWireMock
+ WireMockServer wireMock;
+
+ @Test
+ void test() throws IOException {
+ final var component = Component.newBuilder()
+ .setUuid(UUID.randomUUID().toString())
+ .setPurl("pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4")
+ .build();
+ final var scanCommand = ScanCommand.newBuilder()
+ .setComponent(component)
+ .build();
+ final var scanKey = ScanKey.newBuilder()
+ .setScanToken(UUID.randomUUID().toString())
+ .setComponentUuid(component.getUuid())
+ .build();
+
+ wireMock.stubFor(post(urlPathMatching("/.*"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+ .withResponseBody(Body.ofBinaryOrText(resourceToByteArray("/snyk/one-issue-response.json"), new ContentTypeHeader(MediaType.APPLICATION_OCTET_STREAM)))));
+
+ kafkaCompanion
+ .produce(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanCommand.parser()))
+ .fromRecords(new ProducerRecord<>(KafkaTopic.VULN_ANALYSIS_COMPONENT.getName(), scanKey, scanCommand));
+
+ final ConsumerRecord result = kafkaCompanion
+ .consume(new KafkaProtobufSerde<>(ScanKey.parser()), new KafkaProtobufSerde<>(ScanResult.parser()))
+ .fromTopics(KafkaTopic.VULN_ANALYSIS_RESULT.getName(), 1, Duration.ofSeconds(15))
+ .awaitCompletion()
+ .getFirstRecord();
+
+ assertThat(result.key()).isEqualTo(scanKey);
+ assertThat(result.value().getKey()).isEqualTo(scanKey);
+ assertThat(result.value().getScannerResultsList()).satisfiesExactly(
+ scannerResult -> {
+ assertThat(scannerResult.getStatus()).isEqualTo(ScanStatus.SCAN_STATUS_SUCCESSFUL);
+ assertThat(scannerResult.getScanner()).isEqualTo(Scanner.SCANNER_SNYK);
+ assertThat(scannerResult.getBom().getVulnerabilitiesCount()).isEqualTo(1);
+ assertThat(scannerResult.hasFailureReason()).isFalse();
+ var vuln = scannerResult.getBom().getVulnerabilities(0);
+ assertThat(vuln.getId()).isEqualTo("SNYK-JAVA-COMFASTERXMLJACKSONCORE-3038426");
+ assertThat(vuln.getSource().getName()).isEqualTo("SNYK");
+ assertThat(vuln.getDescription()).isEqualTo("Denial of Service (DoS)");
+ assertThat(vuln.getDetail()).startsWith("## Overview");
+ var rating = vuln.getRatings(0);
+ assertThat(rating.getSource().getName()).isEqualTo("NVD");
+ assertThat(rating.getScore()).isEqualTo(7.5);
+ assertThat(rating.getSeverity()).isEqualTo(Severity.SEVERITY_HIGH);
+ assertThat(rating.getMethod()).isEqualTo(ScoreMethod.SCORE_METHOD_CVSSV31);
+ assertThat(rating.getVector()).isEqualTo("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H");
+ assertThat(vuln.getCwes(0)).isEqualTo(400);
+ assertThat(vuln.getAdvisoriesCount()).isEqualTo(5);
+ assertThat(vuln.getReferences(0).getId()).isEqualTo("CVE-2022-42003");
+ assertThat(vuln.getReferences(0).getSource().getName()).isEqualTo("NVD");
+ assertThat(vuln.getRecommendation()).isEqualTo("Upgrade the package version to 2.12.7.1,2.13.4.2 to fix this vulnerability");
+ }
+ );
+ }
+ }
}
diff --git a/vulnerability-analyzer/src/test/java/org/hyades/processor/scanner/ossindex/OssIndexProcessorTest.java b/vulnerability-analyzer/src/test/java/org/hyades/processor/scanner/ossindex/OssIndexProcessorTest.java
index 8c2b7b13e..d8b044f58 100644
--- a/vulnerability-analyzer/src/test/java/org/hyades/processor/scanner/ossindex/OssIndexProcessorTest.java
+++ b/vulnerability-analyzer/src/test/java/org/hyades/processor/scanner/ossindex/OssIndexProcessorTest.java
@@ -29,7 +29,6 @@
import org.hyades.client.ossindex.OssIndexClient;
import org.hyades.proto.KafkaProtobufDeserializer;
import org.hyades.proto.KafkaProtobufSerializer;
-import org.hyades.proto.vuln.v1.Source;
import org.hyades.proto.vulnanalysis.internal.v1beta1.ScanTask;
import org.hyades.proto.vulnanalysis.v1.Component;
import org.hyades.proto.vulnanalysis.v1.ScanKey;