Skip to content

Commit

Permalink
feat(SBOMER-200): Enhance RPM components found in the container image…
Browse files Browse the repository at this point in the history
… manifests
  • Loading branch information
janinko authored and goldmann committed Nov 20, 2024
1 parent dc3be16 commit da87926
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import java.util.Optional;
import java.util.stream.Collectors;

import com.github.packageurl.MalformedPackageURLException;
import com.github.packageurl.PackageURL;
import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
import org.cyclonedx.model.ExternalReference;
Expand All @@ -46,6 +48,7 @@
import org.jboss.pnc.dto.Artifact;
import org.jboss.sbomer.cli.feature.sbom.adjuster.PncBuildAdjuster;
import org.jboss.sbomer.cli.feature.sbom.service.KojiService;
import org.jboss.sbomer.core.errors.ApplicationException;
import org.jboss.sbomer.core.features.sbom.enums.ProcessorType;
import org.jboss.sbomer.core.features.sbom.utils.RhVersionPattern;
import org.jboss.sbomer.core.features.sbom.utils.SbomUtils;
Expand Down Expand Up @@ -249,7 +252,12 @@ public Bom process(Bom bom) {
break;

default:
processComponent(bom, c);
PackageURL purl = getPackageURL(c);
if ("rpm".equals(purl.getType())) {
processRpmComponent(c, purl);
} else {
processComponent(bom, c);
}
break;
}
}
Expand All @@ -261,6 +269,40 @@ public Bom process(Bom bom) {
return bom;
}

private void processRpmComponent(Component component, PackageURL purl) {
Map<String, String> qualifiers = purl.getQualifiers();
if (qualifiers == null || !qualifiers.containsKey("arch")) {
log.debug("RPM purl is missing arch qualifier: {}", component.getPurl());
return;
}
String arch = qualifiers.get("arch");

KojiBuildInfo buildInfo;
try {
String nvra = purl.getName() + "-" + purl.getVersion() + "." + arch;
buildInfo = kojiService.findBuildByRPM(nvra);
} catch (KojiClientException e) {
log.error("Lookup in Brew failed due to {}", e.getMessage() == null ? e.toString() : e.getMessage(), e);
return;
}

if (buildInfo == null) {
log.warn("No Brew build information was retrieved, will not add any information");
return;
}

// It is a RH image, set publisher and supplier
setPublisher(component);
setSupplier(component);

// Add additional metadata
setBrewBuildMetadata(
component,
String.valueOf(buildInfo.getId()),
Optional.ofNullable(buildInfo.getSource()),
kojiService.getConfig().getKojiWebURL().toString());
}

private void processContainerImageComponent(Component component) {
// Try to find required properties
Optional<Property> componentOpt = SbomUtils
Expand Down Expand Up @@ -300,7 +342,7 @@ private void processContainerImageComponent(Component component) {
setPublisher(component);
setSupplier(component);

// Add aditional metadata
// Add additional metadata
setBrewBuildMetadata(
component,
String.valueOf(buildInfo.getId()),
Expand All @@ -313,4 +355,12 @@ public ProcessorType getType() {
return ProcessorType.DEFAULT;
}

private static PackageURL getPackageURL(Component component) {
try {
return new PackageURL(component.getPurl());
} catch (MalformedPackageURLException e) {
throw new ApplicationException("Unable to parse provided purl: '{}'", component.getPurl(), e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import com.redhat.red.build.koji.model.xmlrpc.KojiRpmInfo;
import org.apache.commons.collections4.MultiValuedMap;
import org.eclipse.microprofile.context.ManagedExecutor;
import org.jboss.pnc.build.finder.core.BuildConfig;
Expand Down Expand Up @@ -202,6 +203,36 @@ public KojiBuild findBuild(Artifact artifact) {
return null;
}

public KojiBuildInfo findBuildByRPM(String nvra) throws KojiClientException {
if (nvra == null) {
return null;
}

log.debug("Finding Brew build for RPM '{}'...", nvra);

List<KojiRpmInfo> rpm = kojiSession.getRPM(List.of(new KojiIdOrName(nvra)));

if (rpm.isEmpty()) {
log.debug("No results found");
return null;
}
KojiRpmInfo rpmInfo = rpm.get(0);
if (rpm.size() > 1) {
log.warn("Multiple RPMs {} found in Brew, this should not happen. Did Kojiji have a breaking change" +
" update? Selected the first one {}", nvra, rpmInfo.getId());
}

if(rpmInfo.getBuildId() == null){
log.debug("RPM {} does not have assigned build", rpmInfo.getId());
return null;
}

KojiBuildInfo buildInfo = kojiSession.getBuild(rpmInfo.getBuildId());

log.debug("Found build: '{}'...", buildInfo.getId());
return buildInfo;
}

public KojiBuildInfo findBuild(String nvr) throws KojiClientException {
if (nvr == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jboss.sbomer.cli.test.unit.feature.sbom;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -83,6 +84,53 @@ void testAddBrewInfo() throws IOException, KojiClientException {

}

@Test
void testAddBrewInfoForRpm() throws IOException, KojiClientException {
PncService pncServiceMock = Mockito.mock(PncService.class);
KojiService kojiServiceMock = Mockito.mock(KojiService.class);

KojiBuildInfo kojiBuildInfo = new KojiBuildInfo();
kojiBuildInfo.setId(12345);
kojiBuildInfo.setSource("https://git.com/repo#hash");

BuildConfig buildConfig = new BuildConfig();
buildConfig.setKojiWebURL(new URL("https://koji.web"));

when(kojiServiceMock.getConfig()).thenReturn(buildConfig);
when(kojiServiceMock.findBuildByRPM(eq("audit-libs-3.0.7-103.el9.x86_64")))
.thenReturn(kojiBuildInfo);

DefaultProcessor defaultProcessor = new DefaultProcessor(pncServiceMock, kojiServiceMock);

Bom bom = SbomUtils.fromString(TestResources.asString("boms/image-after-adjustments.json"));
Bom processed = defaultProcessor.process(bom);

assertEquals(192, processed.getComponents().size());

Component rpmComponent = processed.getComponents().stream()
.filter(c -> "pkg:rpm/redhat/[email protected]?arch=x86_64".equals(c.getPurl()))
.findFirst().orElseThrow();

assertNotNull(rpmComponent.getSupplier());
assertEquals("Red Hat", rpmComponent.getSupplier().getName());
assertEquals("Red Hat", rpmComponent.getPublisher());

ExternalReference buildSystem = SbomUtils.getExternalReferences(rpmComponent, Type.BUILD_SYSTEM).get(0);

assertEquals("https://koji.web/buildinfo?buildID=12345", buildSystem.getUrl());
assertEquals("brew-build-id", buildSystem.getComment());

assertEquals(
"https://git.com/repo#hash",
SbomUtils.getExternalReferences(rpmComponent, Type.VCS).get(0).getUrl());

Commit commit = rpmComponent.getPedigree().getCommits().get(0);

assertEquals("hash", commit.getUid());
assertEquals("https://git.com/repo#hash", commit.getUrl());

}

@Test
void baseTest() throws IOException {
Bom bom = SbomUtils.fromString(TestResources.asString("boms/adjusted.json"));
Expand Down

0 comments on commit da87926

Please sign in to comment.