This is an automated email from the ASF dual-hosted git repository.
epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-mcp.git
The following commit(s) were added to refs/heads/main by this push:
new c800f9d3 refactor(build): read the SBOM with the CycloneDX model
instead of JsonSlurper (#247)
c800f9d3 is described below
commit c800f9d3f2e9b6ca8a7eb060eb0f231bc898fefe
Author: Aditya Parikh <[email protected]>
AuthorDate: Tue Oct 6 14:28:20 2026 -0400
refactor(build): read the SBOM with the CycloneDX model instead of
JsonSlurper (#247)
GenerateBinaryLicense parses the CycloneDX SBOM with cyclonedx-core-java's
JsonParser and typed Bom/Component/License model rather than walking
untyped maps from Groovy's JsonSlurper, which removes the unchecked casts.
cyclonedx-core-java 10.2.1 is the version the org.cyclonedx.bom 2.4.1
plugin (which writes the SBOM) already uses. It is a buildSrc-only
dependency and does not ship. Output is unchanged: the generated LICENSE
is byte-identical.
Signed-off-by: Aditya Parikh <[email protected]>
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
buildSrc/build.gradle.kts | 4 +++
.../apache/solr/mcp/build/GenerateBinaryLicense.kt | 39 ++++++++--------------
2 files changed, 17 insertions(+), 26 deletions(-)
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index d1296d79..5bccab6a 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -36,6 +36,10 @@ dependencies {
// the plugin's upstream releases.
implementation("org.nosphere.apache.rat:org.nosphere.apache.rat.gradle.plugin:0.8.1")
+ // Typed reader for the CycloneDX SBOM. Pinned to the version the
org.cyclonedx.bom plugin
+ // (which writes the SBOM) already uses, so reader and writer share one
model.
+ implementation("org.cyclonedx:cyclonedx-core-java:10.2.1")
+
// Only used by the task unit tests under src/test (the main code needs no
extra deps;
// the Gradle API is provided by the kotlin-dsl plugin).
testImplementation("org.junit.jupiter:junit-jupiter:5.12.2")
diff --git
a/buildSrc/src/main/kotlin/org/apache/solr/mcp/build/GenerateBinaryLicense.kt
b/buildSrc/src/main/kotlin/org/apache/solr/mcp/build/GenerateBinaryLicense.kt
index 077bbb37..3da0c157 100644
---
a/buildSrc/src/main/kotlin/org/apache/solr/mcp/build/GenerateBinaryLicense.kt
+++
b/buildSrc/src/main/kotlin/org/apache/solr/mcp/build/GenerateBinaryLicense.kt
@@ -16,7 +16,8 @@
*/
package org.apache.solr.mcp.build
-import groovy.json.JsonSlurper
+import org.cyclonedx.model.Component
+import org.cyclonedx.parsers.JsonParser
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.file.RegularFileProperty
@@ -90,24 +91,18 @@ abstract class GenerateBinaryLicense : DefaultTask() {
/** Gradle runs this method when the task executes (`@TaskAction`). */
@TaskAction
fun generate() {
- val slurper = JsonSlurper()
-
// 1. Index every SBOM component's licenses by "group:name" and
"group:name:version".
// The version-keyed map is preferred so the exact shipped version
wins; the
// coarser key is the fallback when versions differ between SBOM
and classpath.
- @Suppress("UNCHECKED_CAST")
- val sbomJson = slurper.parse(sbom.get().asFile) as Map<String, Any?>
-
- @Suppress("UNCHECKED_CAST")
- val components = (sbomJson["components"] as? List<Map<String,
Any?>>).orEmpty()
+ val components =
JsonParser().parse(sbom.get().asFile).components.orEmpty()
val byGroupArtifact = HashMap<String, List<License>>()
val byGroupArtifactVersion = HashMap<String, List<License>>()
for (component in components) {
- val group = component["group"] as? String ?: continue
- val name = component["name"] as? String ?: continue
+ val group = component.group ?: continue
+ val name = component.name ?: continue
val licenses = licensesOf(component)
byGroupArtifact["$group:$name"] = licenses
- (component["version"] as? String)?.let {
byGroupArtifactVersion["$group:$name:$it"] = licenses }
+ component.version?.let {
byGroupArtifactVersion["$group:$name:$it"] = licenses }
}
// 2. For each dependency that actually ships, look up its license(s)
in the SBOM and
@@ -166,23 +161,15 @@ abstract class GenerateBinaryLicense : DefaultTask() {
}
/** Distinct (label, url?) licenses of an SBOM component; prefers SPDX id,
else name/expression. */
- private fun licensesOf(component: Map<String, Any?>): List<License> {
+ private fun licensesOf(component: Component): List<License> {
+ val choice = component.licenses ?: return emptyList()
val out = LinkedHashMap<String, String?>()
-
- @Suppress("UNCHECKED_CAST")
- val nodes = component["licenses"] as? List<Map<String, Any?>> ?:
return emptyList()
- for (node in nodes) {
- @Suppress("UNCHECKED_CAST")
- val license = node["license"] as? Map<String, Any?>
- if (license != null) {
- val id = license["id"] as? String
- val label = id ?: (license["name"] as? String) ?: "Unspecified"
- val url = (license["url"] as? String) ?: id?.let { spdxUrl(it)
}
- out.putIfAbsent(label, url)
- } else {
- (node["expression"] as? String)?.let { out.putIfAbsent(it,
null) }
- }
+ for (license in choice.licenses.orEmpty()) {
+ val id = license.id
+ val label = id ?: license.name ?: "Unspecified"
+ out.putIfAbsent(label, license.url ?: id?.let { spdxUrl(it) })
}
+ choice.expression?.value?.let { out.putIfAbsent(it, null) }
return out.map { License(it.key, it.value) }
}