Conversation
…shes, opt-in to reproducible bundle id
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Missing delimiter between path and content in hash
- The deterministic bundle hash now prefixes both path bytes and file bytes with their lengths before updating the digest, removing ambiguous concatenation collisions.
- ✅ Fixed: Platform-dependent newLine breaks cross-OS reproducibility
- The properties file writer now uses explicit "\n" line endings instead of platform-dependent
newLine()to keep output byte-identical across OSes.
- The properties file writer now uses explicit "\n" line endings instead of platform-dependent
Or push these changes by commenting:
@cursor push 13fbb069ed
Preview (13fbb069ed)
diff --git a/src/main/java/io/sentry/UploadSourceBundleMojo.java b/src/main/java/io/sentry/UploadSourceBundleMojo.java
--- a/src/main/java/io/sentry/UploadSourceBundleMojo.java
+++ b/src/main/java/io/sentry/UploadSourceBundleMojo.java
@@ -213,11 +213,11 @@
for (final @NotNull Path file : sortedFiles) {
final @NotNull String relativePath =
collectedSourcesDir.toPath().relativize(file).toString().replace('\\', '/');
- digest.update(relativePath.getBytes(StandardCharsets.UTF_8));
+ updateDigestWithLengthPrefix(digest, relativePath.getBytes(StandardCharsets.UTF_8));
// Include the file content in the hash
final byte[] fileBytes = Files.readAllBytes(file);
- digest.update(fileBytes);
+ updateDigestWithLengthPrefix(digest, fileBytes);
}
}
}
@@ -257,6 +257,12 @@
return new UUID(buffer.getLong(), buffer.getLong()).toString();
}
+ private static void updateDigestWithLengthPrefix(
+ final @NotNull MessageDigest digest, final byte[] data) {
+ digest.update(ByteBuffer.allocate(Integer.BYTES).putInt(data.length).array());
+ digest.update(data);
+ }
+
private void bundleSources(
final @NotNull SentryCliRunner cliRunner,
final @NotNull String bundleId,
@@ -375,11 +381,11 @@
// Write properties without timestamp comment for reproducible builds
// Properties are written in sorted order for consistency
fileWriter.write("# Generated by sentry-maven-plugin");
- fileWriter.newLine();
+ fileWriter.write("\n");
fileWriter.write("io.sentry.build-tool=maven");
- fileWriter.newLine();
+ fileWriter.write("\n");
fileWriter.write("io.sentry.bundle-ids=" + bundleId);
- fileWriter.newLine();
+ fileWriter.write("\n");
final @NotNull Resource resource = new Resource();
resource.setDirectory(sentryBuildDir.getPath());|
|
||
| // Include the file content in the hash | ||
| final byte[] fileBytes = Files.readAllBytes(file); | ||
| digest.update(fileBytes); |
There was a problem hiding this comment.
Missing delimiter between path and content in hash
Medium Severity
The hash computation feeds relativePath bytes and fileBytes into the digest without any separator or length prefix between them. This means two different file trees can produce the same hash — for example, a file named "ab" with content "cd" produces the same digest input as a file named "a" with content "bcd". Adding a delimiter (e.g. a null byte) or a length prefix between the path and content would prevent these ambiguous collisions and make the deterministic bundle ID more robust.
| fileWriter.write("io.sentry.build-tool=maven"); | ||
| fileWriter.newLine(); | ||
| fileWriter.write("io.sentry.bundle-ids=" + bundleId); | ||
| fileWriter.newLine(); |
There was a problem hiding this comment.
Platform-dependent newLine breaks cross-OS reproducibility
Medium Severity
BufferedWriter.newLine() writes the platform-specific line separator (\r\n on Windows, \n on Unix). Since the purpose of this change is to produce reproducible builds, the properties file will differ across operating systems, resulting in different JAR contents. Using an explicit "\n" instead of newLine() would ensure byte-identical output regardless of platform.



📜 Description
Add the ability to calculate the bundleId based on Hashes of filepaths and file contents of the source context.
This allows for reproducible builds by having the bundleId stay the same if no files change.
This is an opt-in feature that can be enabled with:
💡 Motivation and Context
Resolves #213
💚 How did you test it?
📝 Checklist
🔮 Next steps