feat: add CycloneDX SBOM generation and publishing support
feat: add CycloneDX Gradle plugin for standards-based SBOM generation feat: generate SBOM artifacts in JSON and XML formats feat: publish SBOM artifacts in CI and expose them through project reports fix: align CycloneDX task configuration with current plugin task model fix: remove deprecated String-based projectType assignment for Gradle 10 compatibility chore: keep SBOM scope focused on production classpaths only
This commit is contained in:
24
.github/workflows/build.yml
vendored
24
.github/workflows/build.yml
vendored
@@ -42,8 +42,19 @@ jobs:
|
|||||||
- name: Set up Gradle caching and instrumentation
|
- name: Set up Gradle caching and instrumentation
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Execute build, tests, PMD, coverage, Javadoc, and distribution packaging
|
- name: Execute build, tests, PMD, coverage, Javadoc, distribution packaging, and SBOM generation
|
||||||
run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip
|
run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip cyclonedxBom
|
||||||
|
|
||||||
|
- name: Upload SBOM
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: sbom
|
||||||
|
path: |
|
||||||
|
build/reports/sbom/radixor-sbom.json
|
||||||
|
build/reports/sbom/radixor-sbom.xml
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 14
|
||||||
|
|
||||||
- name: Upload test reports
|
- name: Upload test reports
|
||||||
if: always()
|
if: always()
|
||||||
@@ -129,11 +140,14 @@ jobs:
|
|||||||
- name: Set up Gradle caching and instrumentation
|
- name: Set up Gradle caching and instrumentation
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Build release distribution
|
- name: Build release distribution and SBOM
|
||||||
run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip
|
run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip cyclonedxBom
|
||||||
|
|
||||||
- name: Publish GitHub release assets
|
- name: Publish GitHub release assets
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
files: build/distributions/*.zip
|
files: |
|
||||||
|
build/distributions/*.zip
|
||||||
|
build/reports/sbom/radixor-sbom.json
|
||||||
|
build/reports/sbom/radixor-sbom.xml
|
||||||
|
|||||||
19
.github/workflows/pages.yml
vendored
19
.github/workflows/pages.yml
vendored
@@ -48,7 +48,7 @@ jobs:
|
|||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Build reports for publication
|
- name: Build reports for publication
|
||||||
run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport pitest jmh
|
run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport pitest jmh cyclonedxBom
|
||||||
|
|
||||||
- name: Prepare gh-pages worktree
|
- name: Prepare gh-pages worktree
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -100,6 +100,10 @@ jobs:
|
|||||||
JMH_CSV_LATEST_LINK=''
|
JMH_CSV_LATEST_LINK=''
|
||||||
DEPENDENCY_CHECK_LINK=''
|
DEPENDENCY_CHECK_LINK=''
|
||||||
DEPENDENCY_CHECK_LATEST_LINK=''
|
DEPENDENCY_CHECK_LATEST_LINK=''
|
||||||
|
SBOM_JSON_LINK=''
|
||||||
|
SBOM_XML_LINK=''
|
||||||
|
SBOM_JSON_LATEST_LINK=''
|
||||||
|
SBOM_XML_LATEST_LINK=''
|
||||||
|
|
||||||
if [ -d "build/reports/jmh" ]; then
|
if [ -d "build/reports/jmh" ]; then
|
||||||
cp -R build/reports/jmh "${RUN_DIR}/jmh"
|
cp -R build/reports/jmh "${RUN_DIR}/jmh"
|
||||||
@@ -129,6 +133,15 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -d "build/reports/sbom" ]; then
|
||||||
|
cp -R build/reports/sbom "${RUN_DIR}/sbom"
|
||||||
|
cp -R build/reports/sbom "${LATEST_DIR}/sbom"
|
||||||
|
SBOM_JSON_LINK='<li><a href="./sbom/radixor-sbom.json">SBOM (JSON)</a></li>'
|
||||||
|
SBOM_XML_LINK='<li><a href="./sbom/radixor-sbom.xml">SBOM (XML)</a></li>'
|
||||||
|
SBOM_JSON_LATEST_LINK='<li><a href="./builds/latest/sbom/radixor-sbom.json">SBOM (JSON)</a></li>'
|
||||||
|
SBOM_XML_LATEST_LINK='<li><a href="./builds/latest/sbom/radixor-sbom.xml">SBOM (XML)</a></li>'
|
||||||
|
fi
|
||||||
|
|
||||||
cat > "${RUN_DIR}/index.html" <<EOF
|
cat > "${RUN_DIR}/index.html" <<EOF
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -153,6 +166,8 @@ jobs:
|
|||||||
<li><a href="./pmd/main.html">PMD Report</a></li>
|
<li><a href="./pmd/main.html">PMD Report</a></li>
|
||||||
<li><a href="./coverage/">Coverage Report</a></li>
|
<li><a href="./coverage/">Coverage Report</a></li>
|
||||||
${DEPENDENCY_CHECK_LINK:-<li>Dependency Vulnerability Report: not available</li>}
|
${DEPENDENCY_CHECK_LINK:-<li>Dependency Vulnerability Report: not available</li>}
|
||||||
|
${SBOM_JSON_LINK:-<li>SBOM (JSON): not available</li>}
|
||||||
|
${SBOM_XML_LINK:-<li>SBOM (XML): not available</li>}
|
||||||
<li><a href="./pitest/">Mutation Testing Report</a></li>
|
<li><a href="./pitest/">Mutation Testing Report</a></li>
|
||||||
$(
|
$(
|
||||||
[ "${HAS_JMH}" = "true" ] && { echo "${JMH_TXT_LINK:-<li>Benchmark Results (TXT): not available</li>}"; echo "${JMH_CSV_LINK:-<li>Benchmark Results (CSV): not available</li>}"; } \
|
[ "${HAS_JMH}" = "true" ] && { echo "${JMH_TXT_LINK:-<li>Benchmark Results (TXT): not available</li>}"; echo "${JMH_CSV_LINK:-<li>Benchmark Results (CSV): not available</li>}"; } \
|
||||||
@@ -200,6 +215,8 @@ jobs:
|
|||||||
<li><a href="./builds/latest/pmd/main.html">PMD Report</a></li>
|
<li><a href="./builds/latest/pmd/main.html">PMD Report</a></li>
|
||||||
<li><a href="./builds/latest/coverage/">Coverage Report</a></li>
|
<li><a href="./builds/latest/coverage/">Coverage Report</a></li>
|
||||||
${DEPENDENCY_CHECK_LATEST_LINK:-<li>Dependency Vulnerability Report: not currently available</li>}
|
${DEPENDENCY_CHECK_LATEST_LINK:-<li>Dependency Vulnerability Report: not currently available</li>}
|
||||||
|
${SBOM_JSON_LATEST_LINK:-<li>SBOM (JSON): not available</li>}
|
||||||
|
${SBOM_XML_LATEST_LINK:-<li>SBOM (XML): not available</li>}
|
||||||
<li><a href="./builds/latest/pitest/">Mutation Testing Report</a></li>
|
<li><a href="./builds/latest/pitest/">Mutation Testing Report</a></li>
|
||||||
$(
|
$(
|
||||||
[ "${HAS_JMH}" = "true" ] && { echo "${JMH_TXT_LATEST_LINK:-<li>Benchmark Results (TXT): not available</li>}"; echo "${JMH_CSV_LATEST_LINK:-<li>Benchmark Results (CSV): not available</li>}"; } \
|
[ "${HAS_JMH}" = "true" ] && { echo "${JMH_TXT_LATEST_LINK:-<li>Benchmark Results (TXT): not available</li>}"; echo "${JMH_CSV_LATEST_LINK:-<li>Benchmark Results (CSV): not available</li>}"; } \
|
||||||
|
|||||||
21
build.gradle
21
build.gradle
@@ -7,6 +7,7 @@ plugins {
|
|||||||
id 'info.solidsoft.pitest' version '1.19.0'
|
id 'info.solidsoft.pitest' version '1.19.0'
|
||||||
id 'me.champeau.jmh' version '0.7.2'
|
id 'me.champeau.jmh' version '0.7.2'
|
||||||
id 'org.owasp.dependencycheck' version '12.2.1'
|
id 'org.owasp.dependencycheck' version '12.2.1'
|
||||||
|
id 'org.cyclonedx.bom' version '3.2.4'
|
||||||
id 'com.palantir.git-version' version '4.0.0'
|
id 'com.palantir.git-version' version '4.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ group = 'org.egothor.stemmer'
|
|||||||
version = gitVersion(prefix:'release@')
|
version = gitVersion(prefix:'release@')
|
||||||
|
|
||||||
def benchmarkReportsDirectory = layout.buildDirectory.dir('reports/jmh')
|
def benchmarkReportsDirectory = layout.buildDirectory.dir('reports/jmh')
|
||||||
|
def sbomReportsDirectory = layout.buildDirectory.dir('reports/sbom')
|
||||||
|
|
||||||
def nvdApiKey = providers.gradleProperty('nvdApiKey')
|
def nvdApiKey = providers.gradleProperty('nvdApiKey')
|
||||||
.orElse(providers.environmentVariable('NVD_API_KEY'))
|
.orElse(providers.environmentVariable('NVD_API_KEY'))
|
||||||
@@ -124,6 +126,25 @@ tasks.named('check') {
|
|||||||
// no-default, only on-demand: dependsOn(tasks.named('dependencyCheckAnalyze'))
|
// no-default, only on-demand: dependsOn(tasks.named('dependencyCheckAnalyze'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
tasks.matching { it.name == 'cyclonedxDirectBom' }.configureEach {
|
||||||
|
includeConfigs = ['runtimeClasspath', 'compileClasspath']
|
||||||
|
skipConfigs = ['testRuntimeClasspath', 'testCompileClasspath', 'jmh.*', 'mockitoAgent']
|
||||||
|
includeBomSerialNumber = true
|
||||||
|
includeLicenseText = false
|
||||||
|
includeMetadataResolution = true
|
||||||
|
includeBuildSystem = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('cyclonedxBom') {
|
||||||
|
includeBomSerialNumber = true
|
||||||
|
includeLicenseText = false
|
||||||
|
includeBuildSystem = true
|
||||||
|
jsonOutput.set(sbomReportsDirectory.map { it.file('radixor-sbom.json') })
|
||||||
|
xmlOutput.set(sbomReportsDirectory.map { it.file('radixor-sbom.xml') })
|
||||||
|
}
|
||||||
|
|
||||||
pitest {
|
pitest {
|
||||||
pitestVersion = '1.22.1'
|
pitestVersion = '1.22.1'
|
||||||
junit5PluginVersion = '1.2.3'
|
junit5PluginVersion = '1.2.3'
|
||||||
|
|||||||
Reference in New Issue
Block a user