diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4fcc851..7d35cd0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -42,8 +42,19 @@ jobs:
- name: Set up Gradle caching and instrumentation
uses: gradle/actions/setup-gradle@v4
- - name: Execute build, tests, PMD, coverage, Javadoc, and distribution packaging
- run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip
+ - name: Execute build, tests, PMD, coverage, Javadoc, distribution packaging, and SBOM generation
+ 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
if: always()
@@ -129,11 +140,14 @@ jobs:
- name: Set up Gradle caching and instrumentation
uses: gradle/actions/setup-gradle@v4
- - name: Build release distribution
- run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip
+ - name: Build release distribution and SBOM
+ run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip cyclonedxBom
- name: Publish GitHub release assets
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
- files: build/distributions/*.zip
+ files: |
+ build/distributions/*.zip
+ build/reports/sbom/radixor-sbom.json
+ build/reports/sbom/radixor-sbom.xml
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 695a59f..a3be564 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -48,7 +48,7 @@ jobs:
uses: gradle/actions/setup-gradle@v4
- 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
shell: bash
@@ -100,6 +100,10 @@ jobs:
JMH_CSV_LATEST_LINK=''
DEPENDENCY_CHECK_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
cp -R build/reports/jmh "${RUN_DIR}/jmh"
@@ -129,6 +133,15 @@ jobs:
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='
SBOM (JSON)'
+ SBOM_XML_LINK='SBOM (XML)'
+ SBOM_JSON_LATEST_LINK='SBOM (JSON)'
+ SBOM_XML_LATEST_LINK='SBOM (XML)'
+ fi
+
cat > "${RUN_DIR}/index.html" <
@@ -153,6 +166,8 @@ jobs:
PMD Report
Coverage Report
${DEPENDENCY_CHECK_LINK:-Dependency Vulnerability Report: not available}
+ ${SBOM_JSON_LINK:-SBOM (JSON): not available}
+ ${SBOM_XML_LINK:-SBOM (XML): not available}
Mutation Testing Report
$(
[ "${HAS_JMH}" = "true" ] && { echo "${JMH_TXT_LINK:-Benchmark Results (TXT): not available}"; echo "${JMH_CSV_LINK:-Benchmark Results (CSV): not available}"; } \
@@ -200,6 +215,8 @@ jobs:
PMD Report
Coverage Report
${DEPENDENCY_CHECK_LATEST_LINK:-Dependency Vulnerability Report: not currently available}
+ ${SBOM_JSON_LATEST_LINK:-SBOM (JSON): not available}
+ ${SBOM_XML_LATEST_LINK:-SBOM (XML): not available}
Mutation Testing Report
$(
[ "${HAS_JMH}" = "true" ] && { echo "${JMH_TXT_LATEST_LINK:-Benchmark Results (TXT): not available}"; echo "${JMH_CSV_LATEST_LINK:-Benchmark Results (CSV): not available}"; } \
diff --git a/build.gradle b/build.gradle
index 51156c0..304f04d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,6 +7,7 @@ plugins {
id 'info.solidsoft.pitest' version '1.19.0'
id 'me.champeau.jmh' version '0.7.2'
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'
}
@@ -14,6 +15,7 @@ group = 'org.egothor.stemmer'
version = gitVersion(prefix:'release@')
def benchmarkReportsDirectory = layout.buildDirectory.dir('reports/jmh')
+def sbomReportsDirectory = layout.buildDirectory.dir('reports/sbom')
def nvdApiKey = providers.gradleProperty('nvdApiKey')
.orElse(providers.environmentVariable('NVD_API_KEY'))
@@ -124,6 +126,25 @@ tasks.named('check') {
// 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 {
pitestVersion = '1.22.1'
junit5PluginVersion = '1.2.3'