CycloneDX / cyclonedx-gradle-plugin

Creates CycloneDX Software Bill of Materials (SBOM) from Gradle projects
https://cyclonedx.org/
Apache License 2.0
162 stars 77 forks source link

cyclonedxBom task does not finish - endless loop on creating bom #528

Open tkrah opened 1 month ago

tkrah commented 1 month ago

Run the task and it will just loop on:

    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:265)
    at org.gradle.internal.resources.AbstractResourceLockRegistry.getResourceLocksByCurrentThread(AbstractResourceLockRegistry.java:42)
    at org.gradle.internal.work.DefaultWorkerLeaseService.getCurrentWorkerLease(DefaultWorkerLeaseService.java:100)
    at org.gradle.internal.operations.DefaultBuildOperationQueueFactory.create(DefaultBuildOperationQueueFactory.java:33)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.executeInParallel(DefaultBuildOperationExecutor.java:95)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.runAll(DefaultBuildOperationExecutor.java:65)
    at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ParallelResolveArtifactSet$VisitingSet.visit(ParallelResolveArtifactSet.java:66)
    at org.gradle.api.internal.artifacts.DefaultResolvedDependency.sort(DefaultResolvedDependency.java:132)
    at org.gradle.api.internal.artifacts.DefaultResolvedDependency.getModuleArtifacts(DefaultResolvedDependency.java:110)
    at org.cyclonedx.gradle.CycloneDxTask.getJarArtifact(CycloneDxTask.java:446)
    at org.cyclonedx.gradle.CycloneDxTask.dependencyWithoutJarArtifact(CycloneDxTask.java:415)
    at org.cyclonedx.gradle.CycloneDxTask$$Lambda/0x00007bc8c1199510.test(Unknown Source)
    at java.util.stream.MatchOps$1MatchSink.accept(java.base@21.0.4/MatchOps.java:90)
    at java.util.Spliterators$IteratorSpliterator.tryAdvance(java.base@21.0.4/Spliterators.java:1950)
    at java.util.stream.ReferencePipeline.forEachWithCancel(java.base@21.0.4/ReferencePipeline.java:129)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(java.base@21.0.4/AbstractPipeline.java:527)
    at java.util.stream.AbstractPipeline.copyInto(java.base@21.0.4/AbstractPipeline.java:513)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(java.base@21.0.4/AbstractPipeline.java:499)
    at java.util.stream.MatchOps$MatchOp.evaluateSequential(java.base@21.0.4/MatchOps.java:230)
    at java.util.stream.MatchOps$MatchOp.evaluateSequential(java.base@21.0.4/MatchOps.java:196)
    at java.util.stream.AbstractPipeline.evaluate(java.base@21.0.4/AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.anyMatch(java.base@21.0.4/ReferencePipeline.java:632)
    at org.cyclonedx.gradle.CycloneDxTask.lambda$createBom$6(CycloneDxTask.java:357)
    at org.cyclonedx.gradle.CycloneDxTask$$Lambda/0x00007bc8c1052b58.accept(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(java.base@21.0.4/ForEachOps.java:184)
    at java.util.stream.ReferencePipeline$2$1.accept(java.base@21.0.4/ReferencePipeline.java:179)
    at java.util.HashMap$KeySpliterator.forEachRemaining(java.base@21.0.4/HashMap.java:1715)
    at java.util.stream.AbstractPipeline.copyInto(java.base@21.0.4/AbstractPipeline.java:509)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(java.base@21.0.4/AbstractPipeline.java:499)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(java.base@21.0.4/ForEachOps.java:151)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(java.base@21.0.4/ForEachOps.java:174)
    at java.util.stream.AbstractPipeline.evaluate(java.base@21.0.4/AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.forEach(java.base@21.0.4/ReferencePipeline.java:596)
    at org.cyclonedx.gradle.CycloneDxTask.createBom(CycloneDxTask.java:330)

To Reproduce Use this alignment rule to fix some dependencies:

// CVE-2024-38816 + https://github.com/gradle/gradle/issues/9160
class SpringBomAlignmentRule implements ComponentMetadataRule {
    void execute(ComponentMetadataContext ctx) {
        ctx.details.with {
            if (id.group.startsWith("org.springframework")) {
                belongsTo("org.springframework:spring-framework-bom:6.1.14", false)
            }
        }
    }
}

subprojects {
    pluginManager.withPlugin("java") {
        dependencies {
            components.all(SpringBomAlignmentRule)
        }
    }
}

gradle dependencies --configuration productionRuntimeClasspath

does run without a problem, resulting in the correct dependencies.

A workaround which seems to "break" the loop is this:

            if (id.group.startsWith("org.springframework")) {
                if (id.name != "spring-framework-bom") {
                    belongsTo("org.springframework:spring-framework-bom:6.1.14", false)
                }
            }

Expected behavior gradle cyclonedxBom should not loop endlessly.

Environment cyclonedx = { id = 'org.cyclonedx.bom', version = "1.8.2" } - we can't use 1.9.x yet because of https://github.com/CycloneDX/cyclonedx-gradle-plugin/issues/482

gordonrousselle commented 1 month ago

Hi @tkrah Is it possible to provide the full build.gradle that caused this issue?

I have encountered a similar issue (infinite loop) recently. The scenario was a dependency graph which contained a loop between non-jar dependencies. I suspect the same might be happening here, but I would need to understand what dependencies are declared.

tkrah commented 3 weeks ago

Hi @tkrah Is it possible to provide the full build.gradle that caused this issue?

I have encountered a similar issue (infinite loop) recently. The scenario was a dependency graph which contained a loop between non-jar dependencies. I suspect the same might be happening here, but I would need to understand what dependencies are declared.

https://github.com/tkrah/cyclonedx-528

gordonrousselle commented 3 weeks ago

Hi @tkrah. Thanks for sending the full configuration. I have tried it out and as expected it is a loop between non-jar dependencies. More specifically it is the bom org.springframework:spring-framework-bom:6.1.14 that has itself as a dependency. You can easily see this when you run the dependencies gradle task.

Note that the PR #532 is aiming to resolve a lot of existing issue including this one. I have tested it out and it works fine with those changes.

tkrah commented 3 weeks ago

Hi @tkrah. Thanks for sending the full configuration. I have tried it out and as expected it is a loop between non-jar dependencies. More specifically it is the bom org.springframework:spring-framework-bom:6.1.14 that has itself as a dependency. You can easily see this when you run the dependencies gradle task.

Note that the PR #532 is aiming to resolve a lot of existing issue including this one. I have tested it out and it works fine with those changes.

Yeah I knew it had to be this one, because the workaround was to let the alignment rule exclude this bom - thanks for confirming and I am looking forward to #532 .