CycloneDX / CycloneDX/cyclonedx-gradle-plugin

Provide a stable task DSL independent of CycloneDX Core in 4.0

Open
#883 2 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Java
Stars
239
Forks
102
Avg merge
1d 9h
Merged PRs (30d)
11

Description

## User problem

Several task properties currently expose `cyclonedx-core-java` model and enum types directly. This makes ordinary
plugin configuration depend on the implementation library's API and turns core upgrades into migration work for
plugin users.

Users need a configuration surface that is natural in both Groovy and Kotlin, remains stable when CycloneDX Core
evolves, and offers a gradual migration from existing 3.x builds.

## Desired outcome

CycloneDX Gradle Plugin 4.0 provides a plugin-owned, Gradle-native DSL directly on the Direct and Aggregate SBOM tasks.
Users can configure the same effective metadata available through the existing core-backed properties without
constructing CycloneDX Core objects.

The 4.0 experience should have these properties:

- The canonical DSL uses plugin-owned terms and types, with validated string aliases where they improve Groovy and
Kotlin usability.
- It has capability parity with every effective field reachable through the five existing core-backed properties,
rather than attempting to mirror the complete CycloneDX object model.
- Existing 3.x configurations using `schemaVersion`, `projectType`, `organizationalEntity`, `licenseChoice`, and
`externalReferences` remain functional throughout 4.x as a deprecated compatibility facade. Removal is no earlier
than 5.0.
- Canonical and legacy configuration describe one result: equivalent duplicate values are accepted and conflicts fail
with actionable diagnostics rather than silent precedence.
- Migration guidance is mechanical and example-driven for both Groovy and Kotlin. Detectable legacy use produces at
most one migration warning per build.
- The canonical DSL does not expose a raw CycloneDX Core escape hatch.
- CycloneDX 1.7 becomes the default SBOM schema in 4.0 after support is delivered by #832. Explicitly selecting 1.6
remains supported for users who need the previous output contract.

Apart from explicitly documented 4.0 output-contract changes, equivalent legacy and canonical configuration must
produce equivalent parsed CycloneDX meaning. Serializer formatting and irrelevant collection ordering are not
compatibility guarantees.

## Proposed DSL shape

The following examples preserve the direction discussed during planning. They are a reference for the task-local
hierarchy and migration experience, not a commitment to every identifier before Groovy and Kotlin compilation
fixtures validate the final API.

Kotlin, using plugin-owned typed values:

```kotlin
tasks.cyclonedxDirectBom {
bom {
schemaVersion(SchemaVersion.VERSION_17)
projectType(ProjectType.APPLICATION)

organization {
name = "Example"
url("https://example.com")
contact {
name = "Security"
email = "security@example.com"
}
}

licenses {
license {
id = "Apache-2.0"
}
}

externalReference {
type = ExternalReferenceType.WEBSITE
url = "https://example.com/project"
}
}
}
```

Groovy, demonstrating the permanent normalized string aliases:

```groovy
tasks.named("cyclonedxDirectBom") {
bom {
schemaVersion "1.7"
projectType "application"

organization {
name = "Example"
url "https://example.com"
contact {
name = "Security"
email = "security@example.com"
}
}

licenses {
license {
id = "Apache-2.0"
}
}

externalReference {
type = "website"
url = "https://example.com/project"
}
}
}
```

The same `bom` block is available on `cyclonedxBom`. It owns schema selection, the main component, and Metadata
Enrichment only. Dependency selection, project discovery, aggregation membership, outputs, and root-to-member
relationships remain outside this block.

## Architecture outcome

- Configuration remains task-local, as recorded in
[ADR 0003](https://github.com/CycloneDX/cyclonedx-gradle-plugin/blob/master/docs/adr/0003-configure-sbom-tasks-directly.md);
no shared root-owned plugin extension is introduced.
- Gradle-managed DSL values normalize into a plugin-owned internal configuration model. CycloneDX Core types exist
only at the compatibility boundary and in a one-way mapping layer used to build the SBOM.
- The canonical DSL and resolved configuration stay independent of project discovery, aggregation membership,
outgoing variants, and root-to-member dependency-edge policy.
- The design preserves the per-project, variant-based seams required by explicit aggregation in #848 and Project
Isolation in #847. It neither implements nor competes with those issues.
- A shared service may deduplicate a migration diagnostic only. It must not become a mutable registry of projects,
task state, artifacts, aggregation members, or dependency edges.
- SBOM compatibility follows
[ADR 0004](https://github.com/CycloneDX/cyclonedx-gradle-plugin/blob/master/docs/adr/0004-version-the-sbom-output-contract-with-the-plugin.md).
- Java 8 and 11 and the Gradle 8.4 minimum remain supported throughout 4.x.

## Acceptance outcomes

- Documented Groovy and Kotlin examples demonstrate the canonical task-local DSL and the minimal migration from each
legacy property.
- Canonical configuration covers the effective legacy capability surface, including capabilities available with
CycloneDX Core 13 and schema 1.7.
- Existing legacy Groovy and Kotlin configuration fixtures continue to compile and generate valid SBOMs in 4.x.
- Equivalent legacy and canonical configurations are verified through parsed JSON and XML across supported schema
selectors.
- The default-schema change to 1.7 and the one-line opt-back to 1.6 are called out in the 4.0 migration guide.
- Public canonical signatures contain no CycloneDX Core types or Gradle project-topology types.
- Configuration-cache and task-cache behavior account for every effective nested value.

## Out of scope

- Removing the legacy facade before 5.0.
- Mirroring the entire CycloneDX BOM object model.
- Implementing explicit aggregation (#848) or claiming Project Isolation support (#847).
- Replacing the independently tracked implementation of CycloneDX 1.7 support (#832).

Contributor guide

Open the contributing guide

Research direction

Start by reading docs/adr/0003-configure-sbom-tasks-directly.md and docs/adr/0004-version-the-sbom-output-contract-with-the-plugin.md, then trace the five existing core-backed task properties and the Direct and Aggregate SBOM tasks. Use the documented Groovy and Kotlin examples and existing configuration fixtures as the compatibility targets; done means the canonical task-local DSL, legacy facade, migration guidance, parsed-output checks, and cache behavior meet the listed acceptance outcomes.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
build-system, developer-experience, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.