From 961dd30fd707d8c6d8d41c1b9a62439f78529ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honza=20Br=C3=A1zdil?= Date: Thu, 9 Jan 2025 12:32:02 +0100 Subject: [PATCH] fix: parsing of artifact data to get component group/name/version Updated in accordance with: https://github.com/CycloneDX/cyclonedx-node-npm/blob/main/docs/result.md --- .../CycloneDxGenerateOperationCommand.java | 6 +- .../sbom/processor/DefaultProcessor.java | 7 +-- .../feature/sbom/DefaultProcessorTest.java | 7 +++ .../core/features/sbom/utils/SbomUtils.java | 55 ++++++++++--------- 4 files changed, 42 insertions(+), 33 deletions(-) diff --git a/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/command/CycloneDxGenerateOperationCommand.java b/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/command/CycloneDxGenerateOperationCommand.java index 99d4ccce2..cf3005d39 100644 --- a/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/command/CycloneDxGenerateOperationCommand.java +++ b/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/command/CycloneDxGenerateOperationCommand.java @@ -206,13 +206,11 @@ protected Path doGenerate() { // pom.xml) if (!purlToComponents.containsKey(artifact.getArtifact().getPurl())) { KojiBuild brewBuild = null; - BuildType buildType = null; if (artifact.getArtifact().getBuild() != null) { - buildType = artifact.getArtifact().getBuild().getBuildConfigRevision().getBuildType(); + // Artifact was built in PNC, so it has all the data we need } else if (artifact.getBrewId() != null && artifact.getBrewId() > 0) { brewBuild = kojiService.findBuild(artifact.getArtifact()); - buildType = BuildType.MVN; } else { log.warn( "An artifact has been found with no associated build: '{}'. It will be added in the SBOM with generic type.", @@ -220,7 +218,7 @@ protected Path doGenerate() { } // Create a component entry for the artifact - Component component = createComponent(artifact.getArtifact(), Scope.REQUIRED, Type.LIBRARY, buildType); + Component component = createComponent(artifact.getArtifact(), Scope.REQUIRED, Type.LIBRARY); setArtifactMetadata(component, artifact.getArtifact(), pncService.getApiUrl()); setPncBuildMetadata(component, artifact.getArtifact().getBuild(), pncService.getApiUrl()); diff --git a/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/processor/DefaultProcessor.java b/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/processor/DefaultProcessor.java index 865609f4e..1093a15b8 100644 --- a/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/processor/DefaultProcessor.java +++ b/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/processor/DefaultProcessor.java @@ -332,10 +332,10 @@ private void addMissingNpmDependencies(Bom bom, Component component) { return; } - addMissingNpmDependencies(bom, component, npmDependencies, build.getBuildConfigRevision().getBuildType()); + addMissingNpmDependencies(bom, component, npmDependencies); } - private void addMissingNpmDependencies(Bom bom, Component component, Collection npmDependencies, BuildType buildType) { + private void addMissingNpmDependencies(Bom bom, Component component, Collection npmDependencies) { Set listedPurls = bom.getComponents() .stream() .map(DefaultProcessor::getPackageURL) @@ -357,8 +357,7 @@ private void addMissingNpmDependencies(Bom bom, Component component, Collection< Component newComponent = createComponent( artifact, Component.Scope.REQUIRED, - Component.Type.LIBRARY, - buildType); + Component.Type.LIBRARY); setArtifactMetadata(newComponent, artifact, pncService.getApiUrl()); setPncBuildMetadata(newComponent, artifact.getBuild(), pncService.getApiUrl()); bom.addComponent(newComponent); diff --git a/cli/src/test/java/org/jboss/sbomer/cli/test/unit/feature/sbom/DefaultProcessorTest.java b/cli/src/test/java/org/jboss/sbomer/cli/test/unit/feature/sbom/DefaultProcessorTest.java index f8031506b..e5e3e4b4d 100644 --- a/cli/src/test/java/org/jboss/sbomer/cli/test/unit/feature/sbom/DefaultProcessorTest.java +++ b/cli/src/test/java/org/jboss/sbomer/cli/test/unit/feature/sbom/DefaultProcessorTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -216,6 +217,9 @@ private static void verifyAddedNpmDependencies(Bom processed) { assertEquals("https://pnc.example.com/pnc-rest/v2/artifacts/2160610", onceArtifact.getUrl()); assertTrue(getDependency("pkg:npm/once@1.4.0", mainDependency.getDependencies()).isPresent()); assertTrue(getDependency("pkg:npm/once@1.4.0", processed.getDependencies()).isPresent()); + assertNull(componentOnce.getGroup()); + assertEquals("once", componentOnce.getName()); + assertEquals("1.4.0", componentOnce.getVersion()); Component componentKogito = getComponent( processed, @@ -241,6 +245,9 @@ private static void verifyAddedNpmDependencies(Bom processed) { getDependency( "pkg:npm/%40redhat/kogito-tooling-keyboard-shortcuts@0.9.0-2", processed.getDependencies()).isPresent()); + assertEquals("@redhat", componentKogito.getGroup()); + assertEquals("kogito-tooling-keyboard-shortcuts", componentKogito.getName()); + assertEquals("0.9.0-2", componentKogito.getVersion()); } private static Optional getDependency(String ref, List dependencies) { diff --git a/core/src/main/java/org/jboss/sbomer/core/features/sbom/utils/SbomUtils.java b/core/src/main/java/org/jboss/sbomer/core/features/sbom/utils/SbomUtils.java index 0f3bee650..a44f7a53c 100644 --- a/core/src/main/java/org/jboss/sbomer/core/features/sbom/utils/SbomUtils.java +++ b/core/src/main/java/org/jboss/sbomer/core/features/sbom/utils/SbomUtils.java @@ -50,6 +50,8 @@ import java.util.regex.Pattern; import java.util.stream.Stream; +import org.commonjava.atlas.maven.ident.ref.SimpleArtifactRef; +import org.commonjava.atlas.npm.ident.ref.NpmPackageRef; import org.cyclonedx.Version; import org.cyclonedx.exception.GeneratorException; import org.cyclonedx.exception.ParseException; @@ -81,6 +83,7 @@ import org.jboss.pnc.dto.Build; import org.jboss.pnc.dto.DeliverableAnalyzerOperation; import org.jboss.pnc.enums.BuildType; +import org.jboss.pnc.restclient.util.ArtifactUtil; import org.jboss.sbomer.core.features.sbom.Constants; import org.jboss.sbomer.core.features.sbom.config.Config; import org.jboss.sbomer.core.features.sbom.config.OperationConfig; @@ -161,27 +164,33 @@ public static Component createComponent( return component; } - private static void setCoordinates(Component component, String identifier, BuildType buildType) { - - switch (buildType) { - case NPM: - String[] gv = identifier.split(":"); - if (gv.length >= 1) { - component.setGroup(gv[0]); - component.setVersion(gv[1]); + private static void setCoordinates(Component component, Artifact artifact) { + switch (artifact.getTargetRepository().getRepositoryType()) { + case NPM: { + NpmPackageRef coordinates = ArtifactUtil.parseNPMCoordinates(artifact); + String[] scopeName = coordinates.getName().split("/"); + if (scopeName.length == 2) { + component.setGroup(scopeName[0]); + component.setName(scopeName[1]); + } else if (scopeName.length == 1) { + component.setName(scopeName[0]); + } else { + log.warn("Unexpected number of slashes in NPM artifact name {}, using it fully", coordinates.getName()); + component.setName(coordinates.getName()); } + component.setVersion(coordinates.getVersionString()); break; - case MVN: - case GRADLE: - case SBT: - default: - String[] gaecv = identifier.split(":"); - - if (gaecv.length >= 3) { - component.setGroup(gaecv[0]); - component.setName(gaecv[1]); - component.setVersion(gaecv[3]); - } + } + case MAVEN: { + SimpleArtifactRef coordinates = ArtifactUtil.parseMavenCoordinates(artifact); + component.setGroup(coordinates.getGroupId()); + component.setName(coordinates.getArtifactId()); + component.setVersion(coordinates.getVersionString()); + break; + } + default: { + component.setName(artifact.getFilename()); + } } } @@ -311,14 +320,10 @@ public static void setProductMetadata(Component component, OperationConfig confi })); } - public static Component createComponent(Artifact artifact, Scope scope, Type type, BuildType buildType) { + public static Component createComponent(Artifact artifact, Scope scope, Type type) { Component component = new Component(); - if (buildType != null) { - setCoordinates(component, artifact.getIdentifier(), buildType); - } else { - component.setName(artifact.getFilename()); - } + setCoordinates(component, artifact); component.setScope(scope); component.setType(type); component.setPurl(artifact.getPurl());