diff --git a/pom.xml b/pom.xml
index c5bcc833..648ec979 100644
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,10 @@
io.quarkus
quarkus-vertx
+
+ io.quarkus
+ quarkus-hibernate-validator
+
io.quarkus
quarkus-junit5
diff --git a/src/main/java/com/redhat/ecosystemappeng/morpheus/config/AppConfig.java b/src/main/java/com/redhat/ecosystemappeng/morpheus/config/AppConfig.java
new file mode 100644
index 00000000..9f87dbfb
--- /dev/null
+++ b/src/main/java/com/redhat/ecosystemappeng/morpheus/config/AppConfig.java
@@ -0,0 +1,34 @@
+package com.redhat.ecosystemappeng.morpheus.config;
+
+import java.util.List;
+
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
+import io.smallrye.config.WithName;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+
+import io.quarkus.runtime.annotations.StaticInitSafe;
+
+@StaticInitSafe
+@ConfigMapping(prefix = "exploit-iq")
+public interface AppConfig {
+ Image image();
+
+ interface Image {
+ Source source();
+
+ interface Source {
+ @WithName("location-keys")
+ @WithDefault("image.source-location,org.opencontainers.image.source,syft:image:labels:io.openshift.build.source-location")
+ @Size(min = 1, max = 10)
+ List<@NotBlank @Pattern(regexp = "^[a-zA-Z0-9.:_/-]+$", message = "Invalid key format") String> locationKeys();
+
+ @WithName("commit-id-keys")
+ @WithDefault("image.source.commit-id,org.opencontainers.image.revision,syft:image:labels:io.openshift.build.commit.id")
+ @Size(min = 1, max = 10)
+ List<@NotBlank @Pattern(regexp = "^[a-zA-Z0-9.:_/-]+$", message = "Invalid key format") String> commitIdKeys();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/redhat/ecosystemappeng/morpheus/service/ReportService.java b/src/main/java/com/redhat/ecosystemappeng/morpheus/service/ReportService.java
index dac1b363..fd62d94a 100644
--- a/src/main/java/com/redhat/ecosystemappeng/morpheus/service/ReportService.java
+++ b/src/main/java/com/redhat/ecosystemappeng/morpheus/service/ReportService.java
@@ -28,6 +28,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.redhat.ecosystemappeng.morpheus.client.GitHubService;
+import com.redhat.ecosystemappeng.morpheus.config.AppConfig;
import com.redhat.ecosystemappeng.morpheus.model.PaginatedResult;
import com.redhat.ecosystemappeng.morpheus.model.Pagination;
import com.redhat.ecosystemappeng.morpheus.model.Report;
@@ -60,11 +61,6 @@
public class ReportService {
private static final Logger LOGGER = Logger.getLogger(ReportService.class);
-
- private static final String COMMIT_ID_PROPERTY = "syft:image:labels:io.openshift.build.commit.id";
- private static final String COMMIT_ID_PROPERTY_GENERAL = "image.source.commit-id";
- private static final String SOURCE_LOCATION_PROPERTY = "syft:image:labels:io.openshift.build.source-location";
- private static final String SOURCE_LOCATION_PROPERTY_GENERAL = "image.source-location";
private static final String PACKAGE_TYPE_PROPERTY = "syft:package:type";
private static final Pattern PURL_PKG_TYPE = Pattern.compile("pkg\\:(\\w+)\\/.*");
public static final String HOSTED_GITHUB_COM = "github.com";
@@ -73,6 +69,9 @@ public class ReportService {
@RestClient
GitHubService gitHubService;
+ @Inject
+ AppConfig appConfig;
+
@Inject
ReportRepositoryService repository;
@@ -364,35 +363,25 @@ private Set buildLanguagesExtensions(String ecosystem) {
}
}
- private static String getSourceLocationFromMetadataLabels(HashMap properties) {
- String sourceLocationValue = properties.get(SOURCE_LOCATION_PROPERTY_GENERAL);
-
- if(Objects.isNull(sourceLocationValue))
- {
- sourceLocationValue = properties.get(SOURCE_LOCATION_PROPERTY);
- }
-
- if(Objects.isNull(sourceLocationValue))
- {
- throw new IllegalArgumentException("SBOM is missing required field: " + SOURCE_LOCATION_PROPERTY_GENERAL + " or " + SOURCE_LOCATION_PROPERTY);
- }
-
- return sourceLocationValue;
+ private String getSourceLocationFromMetadataLabels(Map properties) {
+ return appConfig.image().source().locationKeys().stream()
+ .map(String::trim)
+ .map(properties::get)
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(
+ "SBOM is missing required field. Checked keys: " + appConfig.image().source().locationKeys()));
}
- private static String getCommitIdFromMetadataLabels(HashMap properties) {
- String commitIdIdValue = properties.get(COMMIT_ID_PROPERTY_GENERAL);
-
- if(Objects.isNull(commitIdIdValue)) {
- commitIdIdValue = properties.get(COMMIT_ID_PROPERTY);
- }
-
- if(Objects.isNull(commitIdIdValue))
- {
- throw new IllegalArgumentException("SBOM is missing required field: " + COMMIT_ID_PROPERTY_GENERAL + " or " + COMMIT_ID_PROPERTY);
- }
- return commitIdIdValue;
+ private String getCommitIdFromMetadataLabels(HashMap properties) {
+ return appConfig.image().source().commitIdKeys().stream()
+ .map(String::trim)
+ .map(properties::get)
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(
+ "SBOM is missing required field. Checked keys: " + appConfig.image().source().commitIdKeys()));
}
private JsonNode buildSbomInfo(ReportRequest request) {
diff --git a/src/test/java/com/redhat/ecosystemappeng/morpheus/service/ReportServiceMetadataKeysTest.java b/src/test/java/com/redhat/ecosystemappeng/morpheus/service/ReportServiceMetadataKeysTest.java
new file mode 100644
index 00000000..1c549bb3
--- /dev/null
+++ b/src/test/java/com/redhat/ecosystemappeng/morpheus/service/ReportServiceMetadataKeysTest.java
@@ -0,0 +1,52 @@
+package com.redhat.ecosystemappeng.morpheus.service;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class ReportServiceMetadataKeysTest {
+
+ private static final String EXPECTED_URL = "https://github.com/openshift/origin";
+ private static final List LOCATION_KEYS = List.of(
+ "image.source-location",
+ "org.opencontainers.image.source",
+ "syft:image:labels:io.openshift.build.source-location");
+
+ static Stream validKeyProvider() {
+ return Stream.of(
+ Arguments.of("image.source-location", "first key"),
+ Arguments.of("org.opencontainers.image.source", "second key (fallback)"),
+ Arguments.of("syft:image:labels:io.openshift.build.source-location", "third key (fallback)"));
+ }
+
+ @ParameterizedTest(name = "should find value using {1}")
+ @MethodSource("validKeyProvider")
+ void shouldFindValueByKey(String key, String description) {
+ Map props = Map.of(key, EXPECTED_URL);
+ String result = findValue(props, LOCATION_KEYS);
+ assertEquals(EXPECTED_URL, result);
+ }
+
+ @Test
+ void shouldThrowWhenNoKeyFound() {
+ Map props = Map.of("wrong-key", "value");
+ var ex = assertThrows(IllegalArgumentException.class,
+ () -> findValue(props, LOCATION_KEYS));
+ assertTrue(ex.getMessage().contains("image.source-location"));
+ }
+
+ private String findValue(Map properties, List keys) {
+ return keys.stream()
+ .map(properties::get)
+ .filter(v -> v != null)
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("Missing key. Checked: " + keys));
+ }
+}
\ No newline at end of file