Repository: CycloneDX/cyclonedx-maven-plugin
Pull request #424 (2023-11-07 11:59:43)

Bump org.apache.maven.plugins:maven-plugin-report-plugin from 3.10.1 to 3.10.2
Bumps [org.apache.maven.plugins:maven-plugin-report-plugin](https://github.com/apache/maven-plugin-tools) from 3.10.1 to 3.10.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/apache/maven-plugin-tools/releases">org.apache.maven.plugins:maven-plugin-report-plugin's releases</a>.</em></p>
<blockquote>
<h2>3.10.2</h2>
<h2><a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12317820&amp;version=12353719">Release Notes - Maven Plugin Tools - Version 3.10.2</a></h2>
<h2>Bug</h2>
<ul>
<li>[<a href="https://issues.apache.org/jira/browse/MPLUGIN-484">MPLUGIN-484</a>] - Downgrade plexus-xml to 3.0.0</li>
</ul>
<h2>Dependency upgrade</h2>
<ul>
<li>[<a href="https://issues.apache.org/jira/browse/MPLUGIN-485">MPLUGIN-485</a>] - Upgrade Parent to 40</li>
<li>[<a href="https://issues.apache.org/jira/browse/MPLUGIN-487">MPLUGIN-487</a>] - Bump org.codehaus.plexus:plexus-java from 1.1.2 to 1.2.0</li>
<li>[<a href="https://issues.apache.org/jira/browse/MPLUGIN-488">MPLUGIN-488</a>] - Bump asmVersion from 9.5 to 9.6</li>
<li>[<a href="https://issues.apache.org/jira/browse/MPLUGIN-489">MPLUGIN-489</a>] - Bump antVersion from 1.10.13 to 1.10.14</li>
<li>[<a href="https://issues.apache.org/jira/browse/MPLUGIN-490">MPLUGIN-490</a>] - Bump org.jsoup:jsoup from 1.16.1 to 1.16.2</li>
<li>[<a href="https://issues.apache.org/jira/browse/MPLUGIN-491">MPLUGIN-491</a>] - Bump org.codehaus.plexus:plexus-testing from 1.1.0 to 1.2.0</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/f6222d6f362bab1682e4682726b758eaa1faa945"><code>f6222d6</code></a> [maven-release-plugin] prepare release maven-plugin-tools-3.10.2</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/b2aa6cd87812a86c3641e786d3721d105d21085a"><code>b2aa6cd</code></a> [MPLUGIN-491] Bump org.codehaus.plexus:plexus-testing from 1.1.0 to 1.2.0 (<a href="https://redirect.github.com/apache/maven-plugin-tools/issues/235">#235</a>)</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/be032eed3de41aaa55d0241e32056816ac082c3d"><code>be032ee</code></a> [MPLUGIN-490] Bump org.jsoup:jsoup from 1.16.1 to 1.16.2 (<a href="https://redirect.github.com/apache/maven-plugin-tools/issues/232">#232</a>)</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/596553cee673fd273f2253f5d535c6bcca14791c"><code>596553c</code></a> [MPLUGIN-489] Bump antVersion from 1.10.13 to 1.10.14 (<a href="https://redirect.github.com/apache/maven-plugin-tools/issues/223">#223</a>)</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/71a7750d7fc7dea4f959332e9172587d297ae74d"><code>71a7750</code></a> [MPLUGIN-488] Bump asmVersion from 9.5 to 9.6.</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/1934c85712a93e735c416ccdf313190bcce39319"><code>1934c85</code></a> [MPLUGIN-485] Upgrade Parent to 40</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/52cf6b5ff5c07ab1d6c0b015ffcfe02b22e84081"><code>52cf6b5</code></a> [MPLUGIN-487] Bump org.codehaus.plexus:plexus-java from 1.1.2 to 1.2.0 (<a href="https://redirect.github.com/apache/maven-plugin-tools/issues/231">#231</a>)</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/fbe2a7ca9fa4636a08fb39e2409456b44e1c9911"><code>fbe2a7c</code></a> [MPLUGIN-484] Downgrade plexus-xml to 3.0.0</li>
<li><a href="https://github.com/apache/maven-plugin-tools/commit/619bb57aeefb2f8f14f98c31d68a8da45f88d9e2"><code>619bb57</code></a> [maven-release-plugin] prepare for next development iteration</li>
<li>See full diff in <a href="https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.10.1...maven-plugin-tools-3.10.2">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.apache.maven.plugins:maven-plugin-report-plugin&package-manager=maven&previous-version=3.10.1&new-version=3.10.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has been open for over 30 days.



Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 8332ef3..9d76359 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,6 +4,10 @@ updates:
     directory: "/"
     schedule:
       interval: "daily"
+    ignore:
+      # JsonUnit `2.x` is the last Java 8 compatible major release
+      - dependency-name: "net.javacrumbs.json-unit:*"
+        update-types: ["version-update:semver-major"]
 
   - package-ecosystem: "github-actions"
     directory: "/"
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index a95be10..88ba90a 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -10,7 +10,7 @@ jobs:
     steps:
     - uses: actions/checkout@v4.1.1
     - name: Set up JDK 1.8
-      uses: actions/setup-java@v3
+      uses: actions/setup-java@v4
       with:
         distribution: 'adopt'
         java-version: '8'
diff --git a/pom.xml b/pom.xml
index 17799cf..63e0bef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -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>2.38.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <dependencyManagement>
@@ -321,7 +327,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-javadoc-plugin</artifactId>
-                    <version>3.6.0</version>
+                    <version>3.6.3</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
@@ -436,7 +442,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-plugin-report-plugin</artifactId>
-                <version>3.10.1</version>
+                <version>3.10.2</version>
             </plugin>
         </plugins>
     </reporting>
diff --git a/src/it/makeBom/verify.groovy b/src/it/makeBom/verify.groovy
index 28f59f0..4f54802 100644
--- a/src/it/makeBom/verify.groovy
+++ b/src/it/makeBom/verify.groovy
@@ -9,7 +9,6 @@ assert bomFileXml.text.contains('<reference type="website"><url>https://github.c
 assert !bomFileXml.text.contains('<property name="maven.optional.unused">')
 
 // Reproducible Builds
-assert !bomFileJson.text.contains('"serialNumber"')
 assert !bomFileJson.text.contains('"timestamp"')
 assert bomFileJson.text.contains('"name" : "cdx:reproducible",')
 assert bomFileJson.text.contains('"value" : "enabled"')
diff --git a/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java b/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java
index 4b50480..34ba8a0 100644
--- a/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java
+++ b/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java
@@ -334,7 +334,6 @@ public abstract class BaseCycloneDxMojo extends AbstractMojo {
 
             if (outputTimestamp != null) {
                 // activate Reproducible Builds mode
-                includeBomSerialNumber = false;
                 metadata.setTimestamp(null);
                 if (schemaVersion().getVersion() >= 1.3) {
                     metadata.addProperty(newProperty("cdx:reproducible", "enabled"));
@@ -342,7 +341,8 @@ public abstract class BaseCycloneDxMojo extends AbstractMojo {
             }
 
             if (schemaVersion().getVersion() >= 1.1 && includeBomSerialNumber) {
-                bom.setSerialNumber("urn:uuid:" + UUID.randomUUID());
+                String serialNumber = generateSerialNumber(metadata.getProperties());
+                bom.setSerialNumber(serialNumber);
             }
 
             if (schemaVersion().getVersion() >= 1.2) {
@@ -371,6 +371,21 @@ public abstract class BaseCycloneDxMojo extends AbstractMojo {
         }
     }
 
+    private String generateSerialNumber(List<Property> properties) {
+        String gav = String.format("%s:%s:%s", project.getGroupId(), project.getArtifactId(), project.getVersion());
+        StringBuilder sb = new StringBuilder(gav);
+        if (properties != null) {
+            for(Property prop: properties) {
+                sb.append(';');
+                sb.append(prop.getName());
+                sb.append('=');
+                sb.append(prop.getValue());
+            }
+        }
+        UUID uuid = UUID.nameUUIDFromBytes(sb.toString().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)) {


Test patch:
diff --git a/src/test/java/org/cyclonedx/maven/Issue420Test.java b/src/test/java/org/cyclonedx/maven/Issue420Test.java
new file mode 100644
index 0000000..9638dcd
--- /dev/null
+++ b/src/test/java/org/cyclonedx/maven/Issue420Test.java
@@ -0,0 +1,73 @@
+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 {
+
+    public Issue420Test(MavenRuntimeBuilder runtimeBuilder) throws Exception {
+        super(runtimeBuilder);
+    }
+
+    @Test
+    public void testDefaults() throws Exception {
+        test(new String[0], "urn:uuid:af111a48-2091-3e2e-ad2e-60b1975b651d");
+    }
+
+    @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"}, "urn:uuid:3e383c4c-ef61-3eba-8214-3ecd46c4bbee");
+    }
+
+    @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);
+        }
+    }
+
+}
diff --git a/src/test/resources/issue-420/module-A/pom.xml b/src/test/resources/issue-420/module-A/pom.xml
new file mode 100644
index 0000000..f4244d8
--- /dev/null
+++ b/src/test/resources/issue-420/module-A/pom.xml
@@ -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>
diff --git a/src/test/resources/issue-420/pom.xml b/src/test/resources/issue-420/pom.xml
new file mode 100644
index 0000000..efae20a
--- /dev/null
+++ b/src/test/resources/issue-420/pom.xml
@@ -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>