Skip to content

Commit

Permalink
Fix incorrect component type in aggregated SBOM
Browse files Browse the repository at this point in the history
In a multimodule Maven project, some submodules configured
with `projectType: application` were incorrectly set to
"library" in the aggregated SBOM. This commit fixes the
issue by ensuring the correct component type is reflected
based on the `projectType` configuration.

Tests were also added to verify the correct component type
assignment.

Fixes #521

Signed-off-by: lonewalker0 <riccardoalberto.costantin@studenti.unipd.it>
  • Loading branch information
lonewalker0 authored and hboutemy committed Nov 11, 2024
1 parent c02b50f commit 4450f3b
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 2 deletions.
33 changes: 31 additions & 2 deletions src/main/java/org/cyclonedx/maven/DefaultModelConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,18 @@
import java.util.Properties;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.apache.maven.model.Plugin;
import org.codehaus.plexus.util.xml.Xpp3Dom;

import java.util.Optional;

@Singleton
@Named
public class DefaultModelConverter implements ModelConverter {
private final Logger logger = LoggerFactory.getLogger(DefaultModelConverter.class);
private static final String CYCLONEDX_GROUP_ID = "org.cyclonedx";
private static final String CYCLONEDX_ARTIFACT_ID = "cyclonedx-maven-plugin";
private static final String PROJECT_TYPE_NODE = "projectType";

@Inject
private MavenSession session;
Expand Down Expand Up @@ -160,8 +167,9 @@ public Component convertMavenDependency(Artifact artifact, Version schemaVersion
final Component component = new Component();
component.setGroup(artifact.getGroupId());
component.setName(artifact.getArtifactId());
component.setVersion(artifact.getBaseVersion());
component.setType(Component.Type.LIBRARY);
component.setVersion(artifact.getBaseVersion());
component.setType(Component.Type.LIBRARY);

try {
logger.debug(BaseCycloneDxMojo.MESSAGE_CALCULATING_HASHES);
component.setHashes(BomUtils.calculateHashes(artifact.getFile(), schemaVersion));
Expand All @@ -177,7 +185,12 @@ public Component convertMavenDependency(Artifact artifact, Version schemaVersion
}
try {
final MavenProject project = getEffectiveMavenProject(artifact);

if (project != null) {
String projectType = getProjectTypeFromPluginConfiguration(project);
if (projectType != null) {
component.setType(resolveProjectType(projectType));
}
extractComponentMetadata(project, component, schemaVersion, includeLicenseText);
}
} catch (ProjectBuildingException e) {
Expand All @@ -191,6 +204,22 @@ public Component convertMavenDependency(Artifact artifact, Version schemaVersion

}

public String getProjectTypeFromPluginConfiguration(MavenProject project) {
return Optional.ofNullable(project.getBuild())
.map(build -> build.getPlugins())
.flatMap(plugins -> plugins.stream()
.filter(plugin -> CYCLONEDX_GROUP_ID.equals(plugin.getGroupId()) &&
CYCLONEDX_ARTIFACT_ID.equals(plugin.getArtifactId()))
.findFirst()
)
.map(Plugin::getConfiguration)
.filter(Xpp3Dom.class::isInstance)
.map(Xpp3Dom.class::cast)
.map(configuration -> configuration.getChild(PROJECT_TYPE_NODE))
.map(Xpp3Dom::getValue)
.orElse(null);
}

private static void setExternalReferences(Component component, ExternalReference[] externalReferences) {
if (externalReferences == null || externalReferences.length == 0) {
return;
Expand Down
104 changes: 104 additions & 0 deletions src/test/java/org/cyclonedx/maven/Issue521Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.cyclonedx.maven;



import org.junit.runner.RunWith;


import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder;
import io.takari.maven.testing.executor.MavenVersions;
import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner;

import static org.junit.jupiter.api.Assertions.assertTrue;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import static org.cyclonedx.maven.TestUtils.readXML;


import java.io.File;
import java.io.IOException;



import org.junit.Test;

@RunWith(MavenJUnitTestRunner.class)
@MavenVersions({"3.6.3"})

public class Issue521Test extends BaseMavenVerifier {

public Issue521Test(MavenRuntimeBuilder runtimeBuilder) throws Exception {
super(runtimeBuilder);

}


@Test
public void testFilePresence() throws Exception {
File projDir = cleanAndBuild("issue-521", null);
assertFileExists(projDir, "target/bom.json");
assertFileExists(projDir, "target/bom.xml");
}

@Test
public void testBomJsonContent() throws Exception {
File projDir = cleanAndBuild("issue-521", null);
verifyBomJsonContains(projDir, "target/bom.json", "issue-521-module1", "application");
}

@Test
public void testBomXmlContent() throws Exception {
File projDir = cleanAndBuild("issue-521", null);
checkBomXml(projDir);
}




private static void assertFileExists(File basedir, String filePath) {
File file = new File(basedir, filePath);
assertTrue(file.exists(), String.format("File %s should exist", filePath));
}

private void verifyBomJsonContains(File basedir, String filePath, String expectedName, String expectedType) throws IOException {
File bomJsonFile = new File(basedir, filePath);
assertTrue(bomJsonFile.exists(), String.format("File %s should exist", filePath));

// Leggi il contenuto del file bom.json e verifica la presenza dei campi desiderati
String bomContents = fileRead(bomJsonFile, true);
assertTrue(bomContents.contains("\"name\" : \"" + expectedName + "\""),
String.format("bom.json should contain a module with name '%s'", expectedName));
assertTrue(bomContents.contains("\"type\" : \"" + expectedType + "\""),
String.format("bom.json should contain a module with type '%s'", expectedType));
}

private void checkBomXml(final File projDir) throws Exception {
final Document bom = readXML(new File(projDir, "target/bom.xml"));

final NodeList componentsList = bom.getElementsByTagName("component");
assertTrue(componentsList.getLength() > 0, "Expected at least one component element");

boolean found=false;
for (int i = 0; i < componentsList.getLength(); i++) {
Element component = (Element) componentsList.item(i);
String name = component.getElementsByTagName("name").item(0).getTextContent();
String type = component.getAttribute("type");

if ("issue-521-module1".equals(name) && "application".equals(type)) {
found = true;
break;
}
}

assertTrue(found, "Expected to find a component with name 'module1' and type 'application'");
}








}
38 changes: 38 additions & 0 deletions src/test/resources/issue-521/module1/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.example</groupId>
<artifactId>issue-521</artifactId>
<version>${revision}</version>
</parent>

<artifactId>issue-521-module1</artifactId>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.1</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>${current.version}</version>
<configuration>
<projectType>application</projectType>
</configuration>

</plugin>
</plugins>
</build>

</project>
24 changes: 24 additions & 0 deletions src/test/resources/issue-521/module2/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.example</groupId>
<artifactId>issue-521</artifactId>
<version>${revision}</version>
</parent>

<artifactId>issue-521-module2</artifactId>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.1</version>
</dependency>
</dependencies>

</project>
64 changes: 64 additions & 0 deletions src/test/resources/issue-521/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>issue-521</artifactId>
<packaging>pom</packaging>
<version>${revision}</version>

<licenses>
<license>
<name>Apache-2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>

<modules>
<module>module1</module>
<module>module2</module>
</modules>

<properties>
<revision>1.0.0</revision>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>${current.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
<configuration>

<schemaVersion>1.4</schemaVersion>
<includeBomSerialNumber>true</includeBomSerialNumber>
<includeCompileScope>true</includeCompileScope>
<includeProvidedScope>false</includeProvidedScope>
<includeRuntimeScope>false</includeRuntimeScope>
<includeSystemScope>false</includeSystemScope>
<includeTestScope>false</includeTestScope>
<includeLicenseText>false</includeLicenseText>
<outputFormat>all</outputFormat>
</configuration>

</plugin>
</plugins>
</build>

</project>

0 comments on commit 4450f3b

Please sign in to comment.