This is an automated email from the ASF dual-hosted git repository.
jdaugherty pushed a commit to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git
The following commit(s) were added to refs/heads/8.0.x by this push:
new fa30af085b Fix sbom exemptions for cli split
fa30af085b is described below
commit fa30af085bd009620dd9a41655e99a0cd2069693
Author: James Daugherty <[email protected]>
AuthorDate: Mon Jul 20 06:48:25 2026 -0500
Fix sbom exemptions for cli split
---
.../org/apache/grails/buildsrc/SbomPlugin.groovy | 26 ++++++++++++++--------
.../apache/grails/buildsrc/SbomPluginSpec.groovy | 26 ++++++++++++++++++++++
2 files changed, 43 insertions(+), 9 deletions(-)
diff --git
a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/SbomPlugin.groovy
b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/SbomPlugin.groovy
index 2931b26e06..531425fe7d 100644
---
a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/SbomPlugin.groovy
+++
b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/SbomPlugin.groovy
@@ -150,6 +150,10 @@ class SbomPlugin implements Plugin<Project> {
'grails-data-hibernate5-dbmigration': [
'pkg:maven/javax.xml.bind/[email protected]?type=jar':
'CDDL-1.1', // api export
],
+ 'grails-data-hibernate5-dbmigration-cli': [
+
'pkg:maven/org.hibernate.common/[email protected]?type=jar':
'LGPL-2.1-only', // hibernate 5 is LGPL, we are migrating to ASF license in
hibernate 7
+
'pkg:maven/org.hibernate/[email protected]?type=jar'
: 'LGPL-2.1-only', // hibernate 5 is LGPL, we are migrating to ASF license
in hibernate 7
+ ],
'grails-data-hibernate7-dbmigration-core': [
'pkg:maven/javax.xml.bind/[email protected]?type=jar':
'CDDL-1.1', // api export
],
@@ -278,6 +282,7 @@ class SbomPlugin implements Plugin<Project> {
def projectName = project.name
def projectPath = project.path
Provider<RegularFile> bomOutput = jsonOutput
+ Provider<String> sbomComponent = componentName
Provider<Boolean> isReproducibleBuildProvider =
project.provider { lookupProperty(project, 'isReproducibleBuild') as boolean }
Provider<ZonedDateTime> buildDateProvider = project.provider {
lookupProperty(project, 'buildDate') as ZonedDateTime }
doLast {
@@ -299,7 +304,7 @@ class SbomPlugin implements Plugin<Project> {
comps.each { c ->
// .licenses => choose a license that is
compatible with ASF policy if multiple licensed
if (c instanceof Map && c.licenses instanceof List
&& !(c.licenses as List).empty) {
- def chosen = pickLicense(logger, projectName,
c['bom-ref'] as String, c.licenses as List)
+ def chosen = pickLicense(logger, projectName,
sbomComponent.get(), c['bom-ref'] as String, c.licenses as List)
if (chosen != null) {
c.licenses = [chosen]
}
@@ -445,14 +450,15 @@ class SbomPlugin implements Plugin<Project> {
*
* @param logger the logger to use for logging
* @param projectName the name of the project (captured at configuration
time)
+ * @param sbomComponent the artifact the SBOM describes (the primary or
cli companion coordinate)
* @param bomRef the bom reference for the dependency
* @param licenseChoices the list of license choices
* @return the chosen license
*/
@CompileDynamic
- private static Object pickLicense(org.gradle.api.logging.Logger logger,
String projectName, String bomRef, List licenseChoices) {
+ static Object pickLicense(org.gradle.api.logging.Logger logger, String
projectName, String sbomComponent, String bomRef, List licenseChoices) {
if (!bomRef) {
- throw new GradleException("No bomRef found for a dependency of
${projectName}, cannot pick license")
+ throw new GradleException("No bomRef found for a dependency of
${sbomComponent}, cannot pick license")
}
logger.info('Picking license for {} from {} choices', bomRef,
licenseChoices.size())
@@ -464,14 +470,14 @@ class SbomPlugin implements Plugin<Project> {
def licenseBlock = LICENSES[licenseId]
if (!licenseBlock) {
- throw new GradleException("Cannot find license information for
id ${licenseId} to use for bomRef ${bomRef} in project ${projectName}")
+ throw new GradleException("Cannot find license information for
id ${licenseId} to use for bomRef ${bomRef} in ${sbomComponent}")
}
return licenseBlock
}
if (!(licenseChoices instanceof List) || licenseChoices.isEmpty()) {
- throw new GradleException("No License was found for dependency:
${bomRef} in project ${projectName}")
+ throw new GradleException("No License was found for dependency:
${bomRef} in ${sbomComponent}")
}
def licenseIds = licenseChoices.findAll { it instanceof Map &&
it.license instanceof Map && it.license.id }
@@ -483,13 +489,15 @@ class SbomPlugin implements Plugin<Project> {
def defaultLicense = licenseChoices[0] // pick the first one found
def defaultLicenseId = defaultLicense.license.id as String
if (defaultLicenseId == null) {
- throw new GradleException("Could not determine License id for
dependency: ${bomRef} in project ${projectName} for value ${defaultLicense}")
+ throw new GradleException("Could not determine License id for
dependency: ${bomRef} in ${sbomComponent} for value ${defaultLicense}")
}
if (!(defaultLicenseId in PREFERRED_LICENSES)) {
- def projectLicenseExemptions = LICENSE_EXCEPTIONS[projectName] ?:
[:]
- def permittedLicense = projectLicenseExemptions.get(bomRef) ==
defaultLicenseId
+ // an exemption may be declared against the project or the
specific SBOM component (e.g. a
+ // cli companion whose runtime classpath differs from the primary
jar)
+ def exemptions = (LICENSE_EXCEPTIONS[projectName] ?: [:]) +
(LICENSE_EXCEPTIONS[sbomComponent] ?: [:])
+ def permittedLicense = exemptions.get(bomRef) == defaultLicenseId
if (!permittedLicense) {
- throw new GradleException("Unpermitted License found for bom
dependency: ${bomRef} in project ${projectName} : ${defaultLicenseId}")
+ throw new GradleException("Unpermitted License found for bom
dependency: ${bomRef} in ${sbomComponent} : ${defaultLicenseId}")
}
}
diff --git
a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/SbomPluginSpec.groovy
b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/SbomPluginSpec.groovy
index 295d59c763..4786a254a9 100644
---
a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/SbomPluginSpec.groovy
+++
b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/SbomPluginSpec.groovy
@@ -18,13 +18,22 @@
*/
package org.apache.grails.buildsrc
+import org.gradle.api.GradleException
import org.gradle.api.Project
+import org.gradle.api.logging.Logging
import org.gradle.api.provider.Property
import org.gradle.testfixtures.ProjectBuilder
import spock.lang.Specification
class SbomPluginSpec extends Specification {
+ private static final def LOGGER = Logging.getLogger(SbomPluginSpec)
+ private static final String HIBERNATE_COMMONS =
'pkg:maven/org.hibernate.common/[email protected]?type=jar'
+
+ private static List lgplChoice() {
+ [[license: [id: 'LGPL-2.1-only']]]
+ }
+
static class FakeCliArtifactExtension {
final Property<String> artifactId
FakeCliArtifactExtension(Property<String> artifactId) {
this.artifactId = artifactId }
@@ -71,4 +80,21 @@ class SbomPluginSpec extends Specification {
then: "the sbom file name tracks the custom name, not the
<project>-cli default"
location.get().asFile.name == 'grails-core-custom-cli-8.0.0-sbom.json'
}
+
+ void "a category-X license is permitted when exempted for the sbom
component (cli companion)"() {
+ expect: "the hibernate 5 LGPL exemption keyed to the dbmigration cli
companion is honoured"
+ SbomPlugin.pickLicense(LOGGER, 'grails-data-hibernate5-dbmigration',
+ 'grails-data-hibernate5-dbmigration-cli', HIBERNATE_COMMONS,
lgplChoice()) != null
+ }
+
+ void "an unexempted category-X license fails naming the sbom component,
not just the project"() {
+ when: "the same LGPL dependency appears in an sbom component with no
matching exemption"
+ SbomPlugin.pickLicense(LOGGER, 'grails-data-hibernate5-dbmigration',
+ 'grails-data-hibernate5-dbmigration', HIBERNATE_COMMONS,
lgplChoice())
+
+ then: "the failure identifies the offending sbom component"
+ GradleException e = thrown(GradleException)
+ e.message.contains('grails-data-hibernate5-dbmigration')
+ e.message.contains('LGPL-2.1-only')
+ }
}