Skip to content

Commit

Permalink
Generate serial numbers deterministically (#420)
Browse files Browse the repository at this point in the history
Signed-off-by: Volkan Yazıcı <volkan@yazi.ci>
  • Loading branch information
vy authored and hboutemy committed Dec 9, 2023
1 parent 9557a6f commit 0148b85
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 2 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-assertj</artifactId>
<version>3.2.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -334,15 +334,15 @@ private void generateBom(String analysis, Metadata metadata, List<Component> com

if (outputTimestamp != null) {
// activate Reproducible Builds mode
includeBomSerialNumber = false;
metadata.setTimestamp(null);
if (schemaVersion().getVersion() >= 1.3) {
metadata.addProperty(newProperty("cdx:reproducible", "enabled"));
}
}

if (schemaVersion().getVersion() >= 1.1 && includeBomSerialNumber) {
bom.setSerialNumber("urn:uuid:" + UUID.randomUUID());
String serialNumber = generateSerialNumber();
bom.setSerialNumber(serialNumber);
}

if (schemaVersion().getVersion() >= 1.2) {
Expand Down Expand Up @@ -371,6 +371,12 @@ private void generateBom(String analysis, Metadata metadata, List<Component> com
}
}

private String generateSerialNumber() {
String seed = String.format("%s:%s:%s", project.getGroupId(), project.getArtifactId(), project.getVersion());
UUID uuid = UUID.nameUUIDFromBytes(seed.getBytes(StandardCharsets.UTF_8));
return String.format("urn:uuid:%s", uuid);
}

private void saveBom(Bom bom) throws ParserConfigurationException, IOException, GeneratorException,
MojoExecutionException {
if ("all".equalsIgnoreCase(outputFormat) || "xml".equalsIgnoreCase(outputFormat)) {
Expand Down
75 changes: 75 additions & 0 deletions src/test/java/org/cyclonedx/maven/Issue420Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.cyclonedx.maven;

import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder;
import io.takari.maven.testing.executor.MavenVersions;
import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.annotation.Nullable;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;

/**
* Verifies that serial numbers are generated deterministically.
*
* @see <a href="https://github.com/CycloneDX/cyclonedx-maven-plugin/issues/420">Issue 420</a>
*/
@RunWith(MavenJUnitTestRunner.class)
@MavenVersions({"3.6.3"})
public class Issue420Test extends BaseMavenVerifier {

private static final String SERIAL_NUMBER = "urn:uuid:f1a73cb3-dab9-3592-a2a9-825cf9eab862";

public Issue420Test(MavenRuntimeBuilder runtimeBuilder) throws Exception {
super(runtimeBuilder);
}

@Test
public void testDefaults() throws Exception {
test(new String[0], SERIAL_NUMBER);
}

@Test
public void testDefaultsWhenSerialNumberIsDisabled() throws Exception {
test(new String[]{"-DincludeBomSerialNumber=false"}, null);
}

@Test
public void testWhenOutputTimestampIsSet() throws Exception {
test(new String[]{"-Dproject.build.outputTimestamp=2023-11-08T00:00:00Z"}, SERIAL_NUMBER);
}

@Test
public void testWhenOutputTimestampIsSetAndSerialNumberIsDisabled() throws Exception {
test(new String[]{"-Dproject.build.outputTimestamp=2023-11-08T00:00:00Z", "-DincludeBomSerialNumber=false"}, null);
}

private void test(String[] cliOptions, @Nullable String expectedSerialNumber) throws Exception {
File projDir = resources.getBasedir("issue-420");
verifier
.forProject(projDir)
.withCliOption("-Dcurrent.version=" + getCurrentVersion())
.withCliOption("-B")
.withCliOption("-Dmaven.test.skip")
.withCliOptions(cliOptions)
.execute("clean", "verify")
.assertErrorFreeLog();
assertSerialNumber(projDir, expectedSerialNumber);
}

private static void assertSerialNumber(File projDir, @Nullable String expectedSerialNumber) throws Exception {
File bomFile = new File(projDir, "target/bom.json");
String bomJson = new String(Files.readAllBytes(bomFile.toPath()), StandardCharsets.UTF_8);
String serialNumberKey = "serialNumber";
if (expectedSerialNumber == null) {
assertThatJson(bomJson).isObject().doesNotContainKey(serialNumberKey);
} else {
assertThatJson(bomJson).isObject().containsEntry(serialNumberKey, expectedSerialNumber);
}
}

}
24 changes: 24 additions & 0 deletions src/test/resources/issue-420/module-A/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-420</artifactId>
<version>${revision}</version>
</parent>

<artifactId>issue-420-module-A</artifactId>

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

</project>
53 changes: 53 additions & 0 deletions src/test/resources/issue-420/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?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-420</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>module-A</module>
</modules>

<properties>
<revision>1.0.0</revision>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.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>verify</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
<configuration>
<outputFormat>json</outputFormat>
</configuration>
</plugin>
</plugins>
</build>

</project>

0 comments on commit 0148b85

Please sign in to comment.