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
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand All @@ -73,6 +69,9 @@ public class ReportService {
@RestClient
GitHubService gitHubService;

@Inject
AppConfig appConfig;

@Inject
ReportRepositoryService repository;

Expand Down Expand Up @@ -364,35 +363,25 @@ private Set<String> buildLanguagesExtensions(String ecosystem) {
}
}

private static String getSourceLocationFromMetadataLabels(HashMap<String, String> 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<String, String> 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<String, String> 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<String, String> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> LOCATION_KEYS = List.of(
"image.source-location",
"org.opencontainers.image.source",
"syft:image:labels:io.openshift.build.source-location");

static Stream<Arguments> 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<String, String> props = Map.of(key, EXPECTED_URL);
String result = findValue(props, LOCATION_KEYS);
assertEquals(EXPECTED_URL, result);
}

@Test
void shouldThrowWhenNoKeyFound() {
Map<String, String> 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<String, String> properties, List<String> keys) {
return keys.stream()
.map(properties::get)
.filter(v -> v != null)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Missing key. Checked: " + keys));
}
}