[PM-27903] feat: Remove Credential Exchange (CXF) dependency on f-droid builds (#7154)

This commit is contained in:
Álison Fernandes
2026-07-16 20:48:48 +00:00
committed by GitHub
parent 9fc9e91af4
commit a52336250e
9 changed files with 101 additions and 3 deletions
+17 -1
View File
@@ -33,6 +33,16 @@ configure<LibraryExtension> {
)
}
}
flavorDimensions += listOf("mode")
productFlavors {
create("standard") {
isDefault = true
dimension = "mode"
}
create("fdroid") {
dimension = "mode"
}
}
compileOptions {
sourceCompatibility(libs.versions.jvmTarget.get())
targetCompatibility(libs.versions.jvmTarget.get())
@@ -46,6 +56,9 @@ kotlin {
}
dependencies {
fun standardImplementation(dependencyNotation: Any) {
add("standardImplementation", dependencyNotation)
}
implementation(project(":annotation"))
implementation(project(":core"))
@@ -57,13 +70,16 @@ dependencies {
implementation(libs.androidx.compose.runtime)
implementation(libs.androidx.credentials)
implementation(libs.androidx.credentials.providerevents)
implementation(libs.androidx.credentials.providerevents.play.services)
implementation(libs.google.hilt.android)
ksp(libs.google.hilt.compiler)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.serialization)
implementation(libs.timber)
// Play Services backend for ProviderEventsManager is not FOSS, so it is excluded from the
// F-Droid flavor. The F-Droid flavor supplies no-op stubs instead.
standardImplementation(libs.androidx.credentials.providerevents.play.services)
testImplementation(platform(libs.junit.bom))
testRuntimeOnly(libs.junit.platform.launcher)
testImplementation(libs.junit.jupiter)
@@ -0,0 +1,24 @@
package com.bitwarden.cxf.importer
import android.content.Context
import androidx.credentials.providerevents.exception.ImportCredentialsUnknownErrorException
import com.bitwarden.annotation.OmitFromCoverage
import com.bitwarden.cxf.importer.model.ImportCredentialsSelectionResult
/**
* F-Droid implementation of [CredentialExchangeImporter]. Credential exchange relies on the
* Play Services backend, which is not available on F-Droid builds, so import is unsupported and
* always reports a failure if invoked.
*/
@OmitFromCoverage
@Suppress("UnusedParameter")
internal class CredentialExchangeImporterImpl(
activity: Context,
) : CredentialExchangeImporter {
override suspend fun importCredentials(
credentialTypes: List<String>,
): ImportCredentialsSelectionResult = ImportCredentialsSelectionResult.Failure(
error = ImportCredentialsUnknownErrorException(),
)
}
@@ -0,0 +1,29 @@
package com.bitwarden.cxf.registry
import android.app.Application
import androidx.credentials.providerevents.transfer.ClearExportResponse
import androidx.credentials.providerevents.transfer.RegisterExportResponse
import com.bitwarden.annotation.OmitFromCoverage
import com.bitwarden.core.data.util.asFailure
import com.bitwarden.cxf.registry.model.RegistrationRequest
/**
* F-Droid implementation of [CredentialExchangeRegistry]. Registration relies on the Play Services
* backend, which is not available on F-Droid builds, so registration is a no-op that always fails.
*/
@OmitFromCoverage
@Suppress("UnusedParameter")
internal class CredentialExchangeRegistryImpl(
application: Application,
) : CredentialExchangeRegistry {
override suspend fun register(
registrationRequest: RegistrationRequest,
): Result<RegisterExportResponse> =
UnsupportedOperationException("Credential exchange is not supported on F-Droid builds.")
.asFailure()
override suspend fun unregister(): Result<ClearExportResponse> =
UnsupportedOperationException("Credential exchange is not supported on F-Droid builds.")
.asFailure()
}
@@ -0,0 +1,22 @@
package com.bitwarden.cxf.importer
import android.app.Activity
import com.bitwarden.cxf.importer.model.ImportCredentialsSelectionResult
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
class CredentialExchangeImporterTest {
private val importer = CredentialExchangeImporterImpl(
activity = mockk<Activity>(relaxed = true),
)
@Test
fun `importCredentials should return Failure`() = runTest {
val result = importer.importCredentials(listOf("basic-auth"))
assertTrue(result is ImportCredentialsSelectionResult.Failure)
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ output-reports:
comments:
active: true
excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**ServiceImpl.kt', '**/testFixtures/**' ]
excludes: [ '**/test/**', '**/testStandard/**', '**/testFdroid/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**ServiceImpl.kt', '**/testFixtures/**' ]
AbsentOrWrongFileLicense:
active: false
licenseTemplateFile: 'license.template'
+8 -1
View File
@@ -143,7 +143,14 @@ platform :android do
desc "Run library module tests for specified modules"
lane :testLibraries do |options|
tasks = options[:target].split(" ").map { |mod| "#{mod}:testDebugUnitTest" }
# Modules with product flavors expose per-flavor test tasks instead of `testDebugUnitTest`.
# For those, run every flavor so both the standard and F-Droid sources are covered.
flavored_module_tasks = {
":cxf" => ["testStandardDebugUnitTest", "testFdroidDebugUnitTest"],
}
tasks = options[:target].split(" ").flat_map { |mod|
(flavored_module_tasks[mod] || ["testDebugUnitTest"]).map { |task| "#{mod}:#{task}" }
}
gradle(tasks: tasks)
end