diff --git a/.github/workflows/build-unified.yml b/.github/workflows/build-unified.yml index 3708ab105d3..89eee1c5ce4 100644 --- a/.github/workflows/build-unified.yml +++ b/.github/workflows/build-unified.yml @@ -245,6 +245,20 @@ jobs: path: app/build/outputs/ retention-days: 7 + - name: Generate SBOM + if: github.actor != 'dependabot[bot]' + continue-on-error: true + run: ./gradlew generateSbom + + - name: Upload SBOM artifact + if: github.actor != 'dependabot[bot]' + continue-on-error: true + uses: actions/upload-artifact@v6 + with: + name: sbom-${{ matrix.flavor }}-${{ matrix.variant }} + path: build/reports/cyclonedx/ + retention-days: 30 + - name: Build summary run: | echo "## Build Summary" >> $GITHUB_STEP_SUMMARY diff --git a/build.gradle.kts b/build.gradle.kts index cd50a665c39..d5fbf8590b1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -49,11 +49,23 @@ allprojects { maven(url = "https://jitpack.io") maven(url = "https://oss.sonatype.org/content/repositories/snapshots") } + tasks.withType().configureEach { + includeConfigs.set(listOf(".*[Rr]untimeClasspath.*")) + skipConfigs.set(listOf(".*[Tt]est.*", ".*[Ll]int.*", ".*[Aa]nnotation.*", ".*[Kk]sp.*")) + } } plugins { id(ScriptPlugins.infrastructure) alias(libs.plugins.ksp) apply false // https://github.com/google/dagger/issues/3965 alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.cyclonedx) +} + +tasks.cyclonedxBom { + includeBomSerialNumber = true + includeLicenseText = false + componentName = "wire-android" } +apply(from = "sbom.gradle.kts") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 820b4c3cdc4..3293d43a065 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -87,6 +87,7 @@ openIdAppAuth = "0.11.1" # Other Tools aboutLibraries = "12.2.4" +cyclonedx = "3.1.0" leakCanary = "2.14" ksp = "2.1.0-1.0.28" @@ -128,6 +129,7 @@ aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "abo ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } screenshot = { id = "com.android.compose.screenshot", version.ref = "screenshot"} compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +cyclonedx = { id = "org.cyclonedx.bom", version.ref = "cyclonedx" } # Home-made convention plugins defined in build-logic wire-android-application = { id = "com.wire.android.application" } diff --git a/sbom.gradle.kts b/sbom.gradle.kts new file mode 100644 index 00000000000..a771d78120d --- /dev/null +++ b/sbom.gradle.kts @@ -0,0 +1,36 @@ +/* + * Wire + * Copyright (C) 2025 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +// SBOM generation: produces aggregate CycloneDX JSON output. +// Plugin application and task configuration live in build.gradle.kts (requires plugin classpath). + +// Set meaningful versions on internal modules for SBOM traceability. +// Without this, wire-android modules report "unspecified" in the BOM. +val wireGitHash: Provider = providers.exec { + commandLine("git", "rev-parse", "--short", "HEAD") +}.standardOutput.asText.map { it.trim() } + +allprojects { + version = wireGitHash.get() +} + +tasks.register("generateSbom") { + group = "reporting" + dependsOn("cyclonedxBom") + description = "Generate SBOM" +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 4f73dacb576..24aa54deccc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,6 +19,7 @@ rootProject.name = "wire-android" pluginManagement { includeBuild("build-logic") repositories { + gradlePluginPortal() mavenCentral() google() maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots")