Skip to content

Commit 4450f3b

Browse files
lonewalker0hboutemy
authored andcommitted
Fix incorrect component type in aggregated SBOM
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>
1 parent c02b50f commit 4450f3b

5 files changed

Lines changed: 261 additions & 2 deletions

File tree

src/main/java/org/cyclonedx/maven/DefaultModelConverter.java

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,18 @@
6060
import java.util.Properties;
6161
import java.util.TreeMap;
6262
import java.util.stream.Collectors;
63+
import org.apache.maven.model.Plugin;
64+
import org.codehaus.plexus.util.xml.Xpp3Dom;
65+
66+
import java.util.Optional;
6367

6468
@Singleton
6569
@Named
6670
public class DefaultModelConverter implements ModelConverter {
6771
private final Logger logger = LoggerFactory.getLogger(DefaultModelConverter.class);
72+
private static final String CYCLONEDX_GROUP_ID = "org.cyclonedx";
73+
private static final String CYCLONEDX_ARTIFACT_ID = "cyclonedx-maven-plugin";
74+
private static final String PROJECT_TYPE_NODE = "projectType";
6875

6976
@Inject
7077
private MavenSession session;
@@ -160,8 +167,9 @@ public Component convertMavenDependency(Artifact artifact, Version schemaVersion
160167
final Component component = new Component();
161168
component.setGroup(artifact.getGroupId());
162169
component.setName(artifact.getArtifactId());
163-
component.setVersion(artifact.getBaseVersion());
164-
component.setType(Component.Type.LIBRARY);
170+
component.setVersion(artifact.getBaseVersion());
171+
component.setType(Component.Type.LIBRARY);
172+
165173
try {
166174
logger.debug(BaseCycloneDxMojo.MESSAGE_CALCULATING_HASHES);
167175
component.setHashes(BomUtils.calculateHashes(artifact.getFile(), schemaVersion));
@@ -177,7 +185,12 @@ public Component convertMavenDependency(Artifact artifact, Version schemaVersion
177185
}
178186
try {
179187
final MavenProject project = getEffectiveMavenProject(artifact);
188+
180189
if (project != null) {
190+
String projectType = getProjectTypeFromPluginConfiguration(project);
191+
if (projectType != null) {
192+
component.setType(resolveProjectType(projectType));
193+
}
181194
extractComponentMetadata(project, component, schemaVersion, includeLicenseText);
182195
}
183196
} catch (ProjectBuildingException e) {
@@ -191,6 +204,22 @@ public Component convertMavenDependency(Artifact artifact, Version schemaVersion
191204

192205
}
193206

207+
public String getProjectTypeFromPluginConfiguration(MavenProject project) {
208+
return Optional.ofNullable(project.getBuild())
209+
.map(build -> build.getPlugins())
210+
.flatMap(plugins -> plugins.stream()
211+
.filter(plugin -> CYCLONEDX_GROUP_ID.equals(plugin.getGroupId()) &&
212+
CYCLONEDX_ARTIFACT_ID.equals(plugin.getArtifactId()))
213+
.findFirst()
214+
)
215+
.map(Plugin::getConfiguration)
216+
.filter(Xpp3Dom.class::isInstance)
217+
.map(Xpp3Dom.class::cast)
218+
.map(configuration -> configuration.getChild(PROJECT_TYPE_NODE))
219+
.map(Xpp3Dom::getValue)
220+
.orElse(null);
221+
}
222+
194223
private static void setExternalReferences(Component component, ExternalReference[] externalReferences) {
195224
if (externalReferences == null || externalReferences.length == 0) {
196225
return;
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package org.cyclonedx.maven;
2+
3+
4+
5+
import org.junit.runner.RunWith;
6+
7+
8+
import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder;
9+
import io.takari.maven.testing.executor.MavenVersions;
10+
import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner;
11+
12+
import static org.junit.jupiter.api.Assertions.assertTrue;
13+
import org.w3c.dom.Document;
14+
import org.w3c.dom.Element;
15+
import org.w3c.dom.NodeList;
16+
import static org.cyclonedx.maven.TestUtils.readXML;
17+
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
22+
23+
24+
import org.junit.Test;
25+
26+
@RunWith(MavenJUnitTestRunner.class)
27+
@MavenVersions({"3.6.3"})
28+
29+
public class Issue521Test extends BaseMavenVerifier {
30+
31+
public Issue521Test(MavenRuntimeBuilder runtimeBuilder) throws Exception {
32+
super(runtimeBuilder);
33+
34+
}
35+
36+
37+
@Test
38+
public void testFilePresence() throws Exception {
39+
File projDir = cleanAndBuild("issue-521", null);
40+
assertFileExists(projDir, "target/bom.json");
41+
assertFileExists(projDir, "target/bom.xml");
42+
}
43+
44+
@Test
45+
public void testBomJsonContent() throws Exception {
46+
File projDir = cleanAndBuild("issue-521", null);
47+
verifyBomJsonContains(projDir, "target/bom.json", "issue-521-module1", "application");
48+
}
49+
50+
@Test
51+
public void testBomXmlContent() throws Exception {
52+
File projDir = cleanAndBuild("issue-521", null);
53+
checkBomXml(projDir);
54+
}
55+
56+
57+
58+
59+
private static void assertFileExists(File basedir, String filePath) {
60+
File file = new File(basedir, filePath);
61+
assertTrue(file.exists(), String.format("File %s should exist", filePath));
62+
}
63+
64+
private void verifyBomJsonContains(File basedir, String filePath, String expectedName, String expectedType) throws IOException {
65+
File bomJsonFile = new File(basedir, filePath);
66+
assertTrue(bomJsonFile.exists(), String.format("File %s should exist", filePath));
67+
68+
// Leggi il contenuto del file bom.json e verifica la presenza dei campi desiderati
69+
String bomContents = fileRead(bomJsonFile, true);
70+
assertTrue(bomContents.contains("\"name\" : \"" + expectedName + "\""),
71+
String.format("bom.json should contain a module with name '%s'", expectedName));
72+
assertTrue(bomContents.contains("\"type\" : \"" + expectedType + "\""),
73+
String.format("bom.json should contain a module with type '%s'", expectedType));
74+
}
75+
76+
private void checkBomXml(final File projDir) throws Exception {
77+
final Document bom = readXML(new File(projDir, "target/bom.xml"));
78+
79+
final NodeList componentsList = bom.getElementsByTagName("component");
80+
assertTrue(componentsList.getLength() > 0, "Expected at least one component element");
81+
82+
boolean found=false;
83+
for (int i = 0; i < componentsList.getLength(); i++) {
84+
Element component = (Element) componentsList.item(i);
85+
String name = component.getElementsByTagName("name").item(0).getTextContent();
86+
String type = component.getAttribute("type");
87+
88+
if ("issue-521-module1".equals(name) && "application".equals(type)) {
89+
found = true;
90+
break;
91+
}
92+
}
93+
94+
assertTrue(found, "Expected to find a component with name 'module1' and type 'application'");
95+
}
96+
97+
98+
99+
100+
101+
102+
103+
104+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<parent>
9+
<groupId>com.example</groupId>
10+
<artifactId>issue-521</artifactId>
11+
<version>${revision}</version>
12+
</parent>
13+
14+
<artifactId>issue-521-module1</artifactId>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>junit</groupId>
19+
<artifactId>junit</artifactId>
20+
<version>4.1</version>
21+
</dependency>
22+
</dependencies>
23+
24+
<build>
25+
<plugins>
26+
<plugin>
27+
<groupId>org.cyclonedx</groupId>
28+
<artifactId>cyclonedx-maven-plugin</artifactId>
29+
<version>${current.version}</version>
30+
<configuration>
31+
<projectType>application</projectType>
32+
</configuration>
33+
34+
</plugin>
35+
</plugins>
36+
</build>
37+
38+
</project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<parent>
9+
<groupId>com.example</groupId>
10+
<artifactId>issue-521</artifactId>
11+
<version>${revision}</version>
12+
</parent>
13+
14+
<artifactId>issue-521-module2</artifactId>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>junit</groupId>
19+
<artifactId>junit</artifactId>
20+
<version>4.1</version>
21+
</dependency>
22+
</dependencies>
23+
24+
</project>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<groupId>com.example</groupId>
9+
<artifactId>issue-521</artifactId>
10+
<packaging>pom</packaging>
11+
<version>${revision}</version>
12+
13+
<licenses>
14+
<license>
15+
<name>Apache-2.0</name>
16+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
17+
</license>
18+
</licenses>
19+
20+
<modules>
21+
<module>module1</module>
22+
<module>module2</module>
23+
</modules>
24+
25+
<properties>
26+
<revision>1.0.0</revision>
27+
<maven.compiler.source>8</maven.compiler.source>
28+
<maven.compiler.target>8</maven.compiler.target>
29+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
30+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
31+
</properties>
32+
33+
<build>
34+
<plugins>
35+
<plugin>
36+
<groupId>org.cyclonedx</groupId>
37+
<artifactId>cyclonedx-maven-plugin</artifactId>
38+
<version>${current.version}</version>
39+
<executions>
40+
<execution>
41+
<phase>package</phase>
42+
<goals>
43+
<goal>makeAggregateBom</goal>
44+
</goals>
45+
</execution>
46+
</executions>
47+
<configuration>
48+
49+
<schemaVersion>1.4</schemaVersion>
50+
<includeBomSerialNumber>true</includeBomSerialNumber>
51+
<includeCompileScope>true</includeCompileScope>
52+
<includeProvidedScope>false</includeProvidedScope>
53+
<includeRuntimeScope>false</includeRuntimeScope>
54+
<includeSystemScope>false</includeSystemScope>
55+
<includeTestScope>false</includeTestScope>
56+
<includeLicenseText>false</includeLicenseText>
57+
<outputFormat>all</outputFormat>
58+
</configuration>
59+
60+
</plugin>
61+
</plugins>
62+
</build>
63+
64+
</project>

0 commit comments

Comments
 (0)