From c2690c7ba26d8fd3c71e98f8356a1fd70fca264f Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Sat, 19 Sep 2026 13:21:00 +0000 Subject: [PATCH 1/3] URL-encode coordinates in reproducible-central report URLs (#249) Render POM coordinates into the Reproducible Central artifact badge and link URLs with each segment URL-encoded, so characters such as &, ?, #, " and / in groupId, artifactId or version cannot break the badge image or inject foreign HTML into the generated site report. --- .../buildinfo/ReproducibleCentralReport.java | 29 ++++++++++--- .../ReproducibleCentralReportTest.java | 42 +++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReportTest.java diff --git a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java index 2d8eeedd..82bbfce6 100644 --- a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java +++ b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java @@ -18,6 +18,9 @@ */ package org.apache.maven.plugins.artifact.buildinfo; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -167,12 +170,8 @@ private void renderReproducibleCentralArtifact(Sink sink, Artifact a) { private void renderReproducibleCentralArtifact( Sink sink, String groupId, String artifactId, String version, String scope) { - String url = "https://jvm-repo-rebuild.github.io/reproducible-central/badge/artifact/" - + groupId.replace('.', '/') + '/' + artifactId + ".html"; - String badge = "https://img.shields.io/reproducible-central/artifact/" + groupId + '/' + artifactId + '/' - + version + "?labelColor=1e5b96"; - sink.link(url); - sink.figureGraphics(badge); + sink.link(reproducibleCentralArtifactUrl(groupId, artifactId)); + sink.figureGraphics(reproducibleCentralArtifactBadgeUrl(groupId, artifactId, version)); sink.link_(); sink.text(' ' + groupId + ':' + artifactId + ':' + version); if (scope != null) { @@ -180,6 +179,24 @@ private void renderReproducibleCentralArtifact( } } + static String reproducibleCentralArtifactUrl(String groupId, String artifactId) { + return "https://jvm-repo-rebuild.github.io/reproducible-central/badge/artifact/" + + encode(groupId).replace('.', '/') + '/' + encode(artifactId) + ".html"; + } + + static String reproducibleCentralArtifactBadgeUrl(String groupId, String artifactId, String version) { + return "https://img.shields.io/reproducible-central/artifact/" + encode(groupId) + '/' + encode(artifactId) + + '/' + encode(version) + "?labelColor=1e5b96"; + } + + private static String encode(String s) { + try { + return URLEncoder.encode(s, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("UTF-8 encoding is not supported", e); + } + } + /** * @deprecated use {@link #getOutputPath()} instead */ diff --git a/src/test/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReportTest.java b/src/test/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReportTest.java new file mode 100644 index 00000000..c60f103d --- /dev/null +++ b/src/test/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReportTest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.artifact.buildinfo; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ReproducibleCentralReportTest { + @Test + void artifactUrlEncodesCoordinates() { + assertEquals( + "https://jvm-repo-rebuild.github.io/reproducible-central/badge/artifact/" + + "com%26pany/example/my%24artifact.html", + ReproducibleCentralReport.reproducibleCentralArtifactUrl("com&pany.example", "my$artifact")); + } + + @Test + void artifactBadgeUrlEncodesCoordinates() { + assertEquals( + "https://img.shields.io/reproducible-central/artifact/com%26pany/my%24artifact/" + + "1.0%2FRC%3F1%23x%22%26?labelColor=1e5b96", + ReproducibleCentralReport.reproducibleCentralArtifactBadgeUrl( + "com&pany", "my$artifact", "1.0/RC?1#x\"&")); + } +} From 9268916f495d63739d1ca6e7b9c5afe494625e0a Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Sat, 26 Sep 2026 14:02:40 +0000 Subject: [PATCH 2/3] Fix URL encoding to replace '+' with '%20' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../plugins/artifact/buildinfo/ReproducibleCentralReport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java index 82bbfce6..7edfc616 100644 --- a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java +++ b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java @@ -191,7 +191,7 @@ static String reproducibleCentralArtifactBadgeUrl(String groupId, String artifac private static String encode(String s) { try { - return URLEncoder.encode(s, StandardCharsets.UTF_8.name()); +return URLEncoder.encode(s, StandardCharsets.UTF_8.name()).replace("+", "%20"); } catch (UnsupportedEncodingException e) { throw new IllegalStateException("UTF-8 encoding is not supported", e); } From d1f517a9dd2d541fe71818f41bff429733e44e6f Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Tue, 29 Sep 2026 06:49:49 -0400 Subject: [PATCH 3/3] spotless --- .../plugins/artifact/buildinfo/ReproducibleCentralReport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java index 7edfc616..a327d632 100644 --- a/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java +++ b/src/main/java/org/apache/maven/plugins/artifact/buildinfo/ReproducibleCentralReport.java @@ -191,7 +191,7 @@ static String reproducibleCentralArtifactBadgeUrl(String groupId, String artifac private static String encode(String s) { try { -return URLEncoder.encode(s, StandardCharsets.UTF_8.name()).replace("+", "%20"); + return URLEncoder.encode(s, StandardCharsets.UTF_8.name()).replace("+", "%20"); } catch (UnsupportedEncodingException e) { throw new IllegalStateException("UTF-8 encoding is not supported", e); }