From 517829e7b0bf628ce4ee8cb43a55adb91ec82023 Mon Sep 17 00:00:00 2001 From: David Perez Date: Fri, 22 Aug 2025 11:33:08 -0500 Subject: [PATCH] Remove the RemoveCardPolicy feature flag (#5770) --- .../components/FeatureFlagListItems.kt | 2 - .../feature/search/SearchViewModel.kt | 27 ++-------- .../exportvault/ExportVaultViewModel.kt | 24 +++------ .../itemlisting/VaultItemListingViewModel.kt | 11 +--- .../ui/vault/feature/vault/VaultViewModel.kt | 22 ++------ .../feature/vault/util/VaultDataExtensions.kt | 6 +-- .../debugmenu/DebugMenuViewModelTest.kt | 2 - .../feature/search/SearchViewModelTest.kt | 41 +-------------- .../exportvault/ExportVaultViewModelTest.kt | 20 +------ .../VaultItemListingViewModelTest.kt | 45 ++-------------- .../ui/vault/feature/vault/VaultScreenTest.kt | 2 +- .../vault/feature/vault/VaultViewModelTest.kt | 52 ++----------------- .../vault/util/VaultDataExtensionsTest.kt | 32 ++++++------ .../components/FeatureFlagListItems.kt | 2 - .../core/data/manager/model/FlagKey.kt | 10 ---- .../core/data/manager/model/FlagKeyTest.kt | 5 -- .../main/res/values/strings_non_localized.xml | 1 - 17 files changed, 49 insertions(+), 255 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt index 341694b4e1..4918cb69f6 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt @@ -30,7 +30,6 @@ fun FlagKey.ListItemContent( FlagKey.CredentialExchangeProtocolExport, FlagKey.CipherKeyEncryption, FlagKey.UserManagedPrivilegedApps, - FlagKey.RemoveCardPolicy, -> { @Suppress("UNCHECKED_CAST") BooleanFlagItem( @@ -79,7 +78,6 @@ private fun FlagKey.getDisplayLabel(): String = when (this) { stringResource(BitwardenString.user_trusted_privileged_app_management) } - FlagKey.RemoveCardPolicy -> stringResource(BitwardenString.remove_card_policy) FlagKey.BitwardenAuthenticationEnabled -> { stringResource(BitwardenString.bitwarden_authentication_enabled) } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt index 11cc8772e0..57b5e903c4 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt @@ -4,7 +4,6 @@ import android.os.Parcelable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.bitwarden.annotation.OmitFromCoverage -import com.bitwarden.core.data.manager.model.FlagKey import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.data.repository.util.baseIconUrl import com.bitwarden.data.repository.util.baseWebSendUrl @@ -27,7 +26,6 @@ import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilitySele import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData import com.x8bit.bitwarden.data.autofill.util.login -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager @@ -69,8 +67,6 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -99,7 +95,6 @@ class SearchViewModel @Inject constructor( private val organizationEventManager: OrganizationEventManager, private val vaultRepo: VaultRepository, private val authRepo: AuthRepository, - featureFlagManager: FeatureFlagManager, environmentRepo: EnvironmentRepository, settingsRepo: SettingsRepository, snackbarRelayManager: SnackbarRelayManager, @@ -155,24 +150,10 @@ class SearchViewModel @Inject constructor( .onEach(::sendAction) .launchIn(viewModelScope) - featureFlagManager - .getFeatureFlagFlow(FlagKey.RemoveCardPolicy) - .flatMapLatest { isFlagEnabled -> - if (isFlagEnabled) { - policyManager - .getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES) - .map { policies -> - policies.map { it.organizationId } - } - } else { - flowOf(emptyList()) - } - } - .map { organizationIds -> - SearchAction.Internal.RestrictItemTypesPolicyUpdateReceive( - restrictItemTypesPolicyOrdIds = organizationIds, - ) - } + policyManager + .getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES) + .map { policies -> policies.map { it.organizationId } } + .map { SearchAction.Internal.RestrictItemTypesPolicyUpdateReceive(it) } .onEach(::sendAction) .launchIn(viewModelScope) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModel.kt index 59756d87f0..db6ce88ded 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModel.kt @@ -4,7 +4,6 @@ import android.net.Uri import android.os.Parcelable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope -import com.bitwarden.core.data.manager.model.FlagKey import com.bitwarden.core.data.util.toFormattedPattern import com.bitwarden.network.model.PolicyTypeJson import com.bitwarden.ui.platform.base.BaseViewModel @@ -19,7 +18,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.PasswordStrengthResult import com.x8bit.bitwarden.data.auth.repository.model.RequestOtpResult import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult import com.x8bit.bitwarden.data.auth.repository.model.VerifyOtpResult -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent @@ -55,7 +53,6 @@ class ExportVaultViewModel @Inject constructor( private val vaultRepository: VaultRepository, private val fileManager: FileManager, private val clock: Clock, - private val featureFlagManager: FeatureFlagManager, private val organizationEventManager: OrganizationEventManager, ) : BaseViewModel( initialState = savedStateHandle[KEY_STATE] @@ -467,19 +464,14 @@ class ExportVaultViewModel @Inject constructor( } private fun getRestrictedItemTypes(): List { - val isRemoveCardPolicyFeatureEnabled = - featureFlagManager.getFeatureFlag(FlagKey.RemoveCardPolicy) - if (!isRemoveCardPolicyFeatureEnabled) { - return emptyList() + val hasActiveRestrictItemTypesPolicy = policyManager + .getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES) + .isNotEmpty() + return if (!hasActiveRestrictItemTypesPolicy) { + emptyList() + } else { + listOf(CipherType.CARD) } - - val hasActiveRestrictItemTypesPolicy = - policyManager.getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES).isNotEmpty() - if (!hasActiveRestrictItemTypesPolicy) { - return emptyList() - } - - return listOf(CipherType.CARD) } } @@ -534,7 +526,7 @@ sealed class ExportVaultEvent { data object NavigateBack : ExportVaultEvent() /** - * Shows a toast with the given [message]. + * Shows a toast with the given [data]. */ data class ShowSnackbar( val data: BitwardenSnackbarData, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index b6e3bcfc9a..3dad532132 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -110,7 +110,6 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -212,15 +211,7 @@ class VaultItemListingViewModel @Inject constructor( policyManager .getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES) - .combine( - featureFlagManager.getFeatureFlagFlow(FlagKey.RemoveCardPolicy), - ) { policies, enabledFlag -> - if (enabledFlag) { - policies.map { it.organizationId } - } else { - emptyList() - } - } + .map { policies -> policies.map { it.organizationId } } .map { VaultItemListingsAction.Internal.RestrictItemTypesPolicyUpdateReceive(it) } .onEach(::sendAction) .launchIn(viewModelScope) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt index 6f6c45287d..25c8f5be37 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModel.kt @@ -3,7 +3,6 @@ package com.x8bit.bitwarden.ui.vault.feature.vault import android.os.Parcelable import androidx.compose.ui.graphics.Color import androidx.lifecycle.viewModelScope -import com.bitwarden.core.data.manager.model.FlagKey import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.core.util.persistentListOfNotNull import com.bitwarden.data.repository.util.baseIconUrl @@ -28,7 +27,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager @@ -67,7 +65,6 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge @@ -99,7 +96,6 @@ class VaultViewModel @Inject constructor( private val specialCircumstanceManager: SpecialCircumstanceManager, private val networkConnectionManager: NetworkConnectionManager, snackbarRelayManager: SnackbarRelayManager, - featureFlagManager: FeatureFlagManager, ) : BaseViewModel( initialState = run { val userState = requireNotNull(authRepository.userStateFlow.value) @@ -194,15 +190,7 @@ class VaultViewModel @Inject constructor( policyManager .getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES) - .combine( - featureFlagManager.getFeatureFlagFlow(FlagKey.RemoveCardPolicy), - ) { policies, enabledFlag -> - if (enabledFlag && policies.isNotEmpty()) { - policies.map { it.organizationId } - } else { - null - } - } + .map { policies -> policies.map { it.organizationId } } .map { VaultAction.Internal.PolicyUpdateReceive(it) } .onEach(::sendAction) .launchIn(viewModelScope) @@ -265,7 +253,7 @@ class VaultViewModel @Inject constructor( val excludedOptions = persistentListOfNotNull( CreateVaultItemType.SSH_KEY, CreateVaultItemType.CARD.takeUnless { - state.restrictItemTypesPolicyOrgIds.isNullOrEmpty() + state.restrictItemTypesPolicyOrgIds.isEmpty() }, ) @@ -1045,7 +1033,7 @@ data class VaultState( private val isPullToRefreshSettingEnabled: Boolean, val baseIconUrl: String, val isIconLoadingDisabled: Boolean, - val restrictItemTypesPolicyOrgIds: List?, + val restrictItemTypesPolicyOrgIds: List, ) : Parcelable { /** @@ -1738,7 +1726,7 @@ sealed class VaultAction { * Indicates that a policy update has been received. */ data class PolicyUpdateReceive( - val restrictItemTypesPolicyOrdIds: List?, + val restrictItemTypesPolicyOrdIds: List, ) : Internal() /** @@ -1763,7 +1751,7 @@ private fun MutableStateFlow.updateToErrorStateOrDialog( errorTitle: Text, errorMessage: Text, isRefreshing: Boolean, - restrictItemTypesPolicyOrgIds: List?, + restrictItemTypesPolicyOrgIds: List, ) { this.update { if (vaultData != null) { diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensions.kt index 1743131c72..249463afcc 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensions.kt @@ -42,13 +42,13 @@ fun VaultData.toViewState( isIconLoadingDisabled: Boolean, baseIconUrl: String, vaultFilterType: VaultFilterType, - restrictItemTypesPolicyOrgIds: List?, + restrictItemTypesPolicyOrgIds: List, ): VaultState.ViewState { val filteredCipherViewListWithDeletedItems = decryptCipherListResult .successes - .applyRestrictItemTypesPolicy(restrictItemTypesPolicyOrgIds ?: emptyList()) + .applyRestrictItemTypesPolicy(restrictItemTypesPolicyOrgIds) .toFilteredList(vaultFilterType) val filteredCipherViewList = filteredCipherViewListWithDeletedItems @@ -154,7 +154,7 @@ fun VaultData.toViewState( trashItemsCount = filteredCipherViewListWithDeletedItems.count { it.deletedDate != null }, - showCardGroup = cardCount != 0 || restrictItemTypesPolicyOrgIds == null, + showCardGroup = cardCount != 0 || restrictItemTypesPolicyOrgIds.isEmpty(), ) } } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt index ee437b6d03..3ffd56336a 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt @@ -147,14 +147,12 @@ private val DEFAULT_MAP_VALUE: ImmutableMap, Any> = persistentMapOf FlagKey.CredentialExchangeProtocolImport to true, FlagKey.CredentialExchangeProtocolExport to true, FlagKey.UserManagedPrivilegedApps to true, - FlagKey.RemoveCardPolicy to true, ) private val UPDATED_MAP_VALUE: ImmutableMap, Any> = persistentMapOf( FlagKey.CredentialExchangeProtocolImport to false, FlagKey.CredentialExchangeProtocolExport to false, FlagKey.UserManagedPrivilegedApps to false, - FlagKey.RemoveCardPolicy to false, ) private val DEFAULT_STATE = DebugMenuState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt index fff87aa4f0..0a736731b9 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt @@ -4,7 +4,6 @@ import android.net.Uri import androidx.lifecycle.SavedStateHandle import app.cash.turbine.test import app.cash.turbine.turbineScope -import com.bitwarden.core.data.manager.model.FlagKey import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow import com.bitwarden.data.datasource.disk.base.FakeDispatcherManager @@ -31,7 +30,6 @@ import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilitySele import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManagerImpl import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl @@ -158,13 +156,6 @@ class SearchViewModelTest : BaseViewModelTest() { } returns mutableSnackbarDataFlow } - private val mutableRemoveCardPolicyFeatureFlow = MutableStateFlow(false) - private val featureFlagManager: FeatureFlagManager = mockk { - every { - getFeatureFlagFlow(FlagKey.RemoveCardPolicy) - } returns mutableRemoveCardPolicyFeatureFlow - } - @BeforeEach fun setup() { mockkStatic( @@ -1676,10 +1667,8 @@ class SearchViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is enable`() = + fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly`() = runTest { - mutableRemoveCardPolicyFeatureFlow.value = true - val viewModel = createViewModel() assertEquals( DEFAULT_STATE.copy(restrictItemTypesPolicyOrgIds = persistentListOf()), @@ -1705,33 +1694,6 @@ class SearchViewModelTest : BaseViewModelTest() { ) } - @Suppress("MaxLineLength") - @Test - fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is disabled`() = - runTest { - val viewModel = createViewModel() - assertEquals( - DEFAULT_STATE, - viewModel.stateFlow.value, - ) - mutableActivePoliciesFlow.emit( - listOf( - SyncResponseJson.Policy( - organizationId = "Test Organization", - id = "testId", - type = PolicyTypeJson.RESTRICT_ITEM_TYPES, - isEnabled = true, - data = null, - ), - ), - ) - - assertEquals( - DEFAULT_STATE.copy(restrictItemTypesPolicyOrgIds = persistentListOf()), - viewModel.stateFlow.value, - ) - } - @Test fun `DecryptCipherErrorReceive should display error dialog`() = runTest { val viewModel = createViewModel() @@ -1799,7 +1761,6 @@ class SearchViewModelTest : BaseViewModelTest() { autofillSelectionManager = autofillSelectionManager, organizationEventManager = organizationEventManager, snackbarRelayManager = snackbarRelayManager, - featureFlagManager = featureFlagManager, ) /** diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt index f82b843fc4..9c0ea4c67d 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt @@ -3,7 +3,6 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.exportvault import android.net.Uri import androidx.lifecycle.SavedStateHandle import app.cash.turbine.test -import com.bitwarden.core.data.manager.model.FlagKey import com.bitwarden.data.repository.model.Environment import com.bitwarden.exporters.ExportFormat import com.bitwarden.network.model.PolicyTypeJson @@ -20,7 +19,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.RequestOtpResult import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult import com.x8bit.bitwarden.data.auth.repository.model.VerifyOtpResult -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState @@ -81,13 +79,6 @@ class ExportVaultViewModelTest : BaseViewModelTest() { } returns ExportVaultDataResult.Success("data") } private val fileManager: FileManager = mockk() - - private val featureFlagManager: FeatureFlagManager = mockk { - every { - getFeatureFlag(FlagKey.RemoveCardPolicy) - } returns false - } - private val organizationEventManager = mockk { every { trackEvent(event = any()) } just runs } @@ -143,7 +134,7 @@ class ExportVaultViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString with restricted item types when policy and feature flags enabled`() { + fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString with restricted item types when policy`() { val password = "password" coEvery { authRepository.validatePassword( @@ -153,9 +144,6 @@ class ExportVaultViewModelTest : BaseViewModelTest() { every { policyManager.getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES) } returns listOf(createMockPolicy()) - every { - featureFlagManager.getFeatureFlag(FlagKey.RemoveCardPolicy) - } returns true val viewModel = createViewModel() viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password)) @@ -172,16 +160,13 @@ class ExportVaultViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString without restricted item types when policy is disabled and feature flag is enabled`() { + fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString without restricted item types when policy is disabled`() { val password = "password" coEvery { authRepository.validatePassword( password = password, ) } returns ValidatePasswordResult.Success(isValid = true) - every { - featureFlagManager.getFeatureFlag(FlagKey.RemoveCardPolicy) - } returns true val viewModel = createViewModel() viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password)) @@ -845,7 +830,6 @@ class ExportVaultViewModelTest : BaseViewModelTest() { fileManager = fileManager, vaultRepository = vaultRepository, clock = clock, - featureFlagManager = featureFlagManager, organizationEventManager = organizationEventManager, ) } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt index a241a30c17..8af1af3a95 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt @@ -250,14 +250,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { coEvery { addTrustedPrivilegedApp(any(), any()) } just runs } - private val mutableRemoveCardPolicyFeatureFlow = MutableStateFlow(false) private val featureFlagManager: FeatureFlagManager = mockk { - every { - getFeatureFlagFlow(FlagKey.RemoveCardPolicy) - } returns mutableRemoveCardPolicyFeatureFlow - every { - getFeatureFlag(FlagKey.UserManagedPrivilegedApps) - } returns true + every { getFeatureFlag(FlagKey.UserManagedPrivilegedApps) } returns true } private val initialState = createVaultItemListingState() @@ -376,10 +370,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is enable`() = + fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly`() = runTest { - mutableRemoveCardPolicyFeatureFlow.value = true - val viewModel = createVaultItemListingViewModel() assertEquals( initialState.copy(restrictItemTypesPolicyOrgIds = persistentListOf()), @@ -405,33 +397,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { ) } - @Suppress("MaxLineLength") - @Test - fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is disabled`() = - runTest { - val viewModel = createVaultItemListingViewModel() - assertEquals( - initialState, - viewModel.stateFlow.value, - ) - mutableActivePoliciesFlow.emit( - listOf( - SyncResponseJson.Policy( - organizationId = "Test Organization", - id = "testId", - type = PolicyTypeJson.RESTRICT_ITEM_TYPES, - isEnabled = true, - data = null, - ), - ), - ) - - assertEquals( - initialState.copy(restrictItemTypesPolicyOrgIds = persistentListOf()), - viewModel.stateFlow.value, - ) - } - @Test fun `on LockAccountClick should call lockVault for the given account`() { val accountUserId = "userId" @@ -1392,7 +1357,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { @Test fun `AddVaultItemClick inside a folder should hide card item selection dialog state when RESTRICT_ITEM_TYPES policy is enabled`() = runTest { - mutableRemoveCardPolicyFeatureFlow.value = true val viewModel = createVaultItemListingViewModel( savedStateHandle = createSavedStateHandleWithVaultItemListingType( vaultItemListingType = VaultItemListingType.Folder(folderId = "id"), @@ -1431,7 +1395,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { @Test fun `AddVaultItemClick inside a collection should hide card item selection dialog state when RESTRICT_ITEM_TYPES policy is enabled`() = runTest { - mutableRemoveCardPolicyFeatureFlow.value = true val viewModel = createVaultItemListingViewModel( savedStateHandle = createSavedStateHandleWithVaultItemListingType( vaultItemListingType = VaultItemListingType.Collection(collectionId = "id"), @@ -5014,8 +4977,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { title = BitwardenString.an_error_has_occurred.asText(), message = BitwardenString - .credential_operation_failed_because_user_verification_was_cancelled - .asText(), + .credential_operation_failed_because_user_verification_was_cancelled + .asText(), ), viewModel.stateFlow.value.dialogState, ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt index 0a6028e6fe..126824288c 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt @@ -2071,7 +2071,7 @@ private val DEFAULT_STATE: VaultState = VaultState( isRefreshing = false, showImportActionCard = false, flightRecorderSnackBar = null, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt index bf1eaa7250..87b8bd8c3a 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt @@ -1,7 +1,6 @@ package com.x8bit.bitwarden.ui.vault.feature.vault import app.cash.turbine.test -import com.bitwarden.core.data.manager.model.FlagKey import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow import com.bitwarden.data.repository.model.Environment @@ -25,7 +24,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager @@ -171,13 +169,6 @@ class VaultViewModelTest : BaseViewModelTest() { every { trackEvent(event = any()) } just runs } - private val mutableRemoveCardPolicyFeatureFlow = MutableStateFlow(false) - private val mutableSshKeyVaultItemsEnabledFlow = MutableStateFlow(false) - private val featureFlagManager: FeatureFlagManager = mockk { - every { - getFeatureFlagFlow(FlagKey.RemoveCardPolicy) - } returns mutableRemoveCardPolicyFeatureFlow - } private val reviewPromptManager: ReviewPromptManager = mockk() private val specialCircumstanceManager: SpecialCircumstanceManager = mockk { @@ -219,7 +210,6 @@ class VaultViewModelTest : BaseViewModelTest() { ) } - @Suppress("MaxLineLength") @Test fun `UserState updates with a non-null value when switching accounts should do nothing`() { val viewModel = createViewModel() @@ -414,10 +404,8 @@ class VaultViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is enable`() = + fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly`() = runTest { - mutableRemoveCardPolicyFeatureFlow.value = true - val viewModel = createViewModel() assertEquals( DEFAULT_STATE, @@ -441,33 +429,6 @@ class VaultViewModelTest : BaseViewModelTest() { ) } - @Suppress("MaxLineLength") - @Test - fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is disabled`() = - runTest { - val viewModel = createViewModel() - assertEquals( - DEFAULT_STATE, - viewModel.stateFlow.value, - ) - mutableActivePoliciesFlow.emit( - listOf( - SyncResponseJson.Policy( - organizationId = "Test Organization", - id = "testId", - type = PolicyTypeJson.RESTRICT_ITEM_TYPES, - isEnabled = true, - data = null, - ), - ), - ) - - assertEquals( - DEFAULT_STATE.copy(restrictItemTypesPolicyOrgIds = null), - viewModel.stateFlow.value, - ) - } - @Test fun `Flight Recorder changes should update flightRecorderSnackbar accordingly`() = runTest { mockkStatic(FlightRecorderDataSet::toSnackbarData) @@ -724,7 +685,7 @@ class VaultViewModelTest : BaseViewModelTest() { isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled, baseIconUrl = viewModel.stateFlow.value.baseIconUrl, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ), ) .copy( @@ -749,7 +710,7 @@ class VaultViewModelTest : BaseViewModelTest() { isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled, baseIconUrl = viewModel.stateFlow.value.baseIconUrl, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ), ), viewModel.stateFlow.value, @@ -759,7 +720,6 @@ class VaultViewModelTest : BaseViewModelTest() { @Test fun `vaultDataStateFlow Loaded with items should update state to Content`() = runTest { - mutableSshKeyVaultItemsEnabledFlow.value = true mutableVaultDataStateFlow.tryEmit( value = DataState.Loaded( data = VaultData( @@ -1212,7 +1172,6 @@ class VaultViewModelTest : BaseViewModelTest() { ) } - @Suppress("MaxLineLength") @Test fun `vaultDataStateFlow NoNetwork with items should update state to Content`() = runTest { @@ -1313,7 +1272,6 @@ class VaultViewModelTest : BaseViewModelTest() { @Test fun `vaultDataStateFlow Loaded should include SSH key vault items`() = runTest { - mutableSshKeyVaultItemsEnabledFlow.value = true mutableVaultDataStateFlow.tryEmit( value = DataState.Loaded( data = VaultData( @@ -2593,7 +2551,6 @@ class VaultViewModelTest : BaseViewModelTest() { @Test fun `SelectAddItemType action should set dialog state to SelectVaultAddItemType accordingly when RESTRICT_ITEM_TYPES is enabled`() = runTest { - mutableRemoveCardPolicyFeatureFlow.value = true val viewModel = createViewModel() mutableActivePoliciesFlow.emit( listOf( @@ -2672,7 +2629,6 @@ class VaultViewModelTest : BaseViewModelTest() { settingsRepository = settingsRepository, vaultRepository = vaultRepository, organizationEventManager = organizationEventManager, - featureFlagManager = featureFlagManager, firstTimeActionManager = firstTimeActionManager, snackbarRelayManager = snackbarRelayManager, reviewPromptManager = reviewPromptManager, @@ -2787,5 +2743,5 @@ private fun createMockVaultState( showImportActionCard = true, isRefreshing = false, flightRecorderSnackBar = null, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensionsTest.kt index 9fc6091993..f1168540f2 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/VaultDataExtensionsTest.kt @@ -72,7 +72,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -144,7 +144,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.MyVault, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -204,7 +204,7 @@ class VaultDataExtensionsTest { organizationName = "Mock Organization 1", ), hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -262,7 +262,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -289,7 +289,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -317,7 +317,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -359,7 +359,7 @@ class VaultDataExtensionsTest { isIconLoadingDisabled = false, baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -403,7 +403,7 @@ class VaultDataExtensionsTest { isIconLoadingDisabled = false, baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -447,7 +447,7 @@ class VaultDataExtensionsTest { isIconLoadingDisabled = false, baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -675,7 +675,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -719,7 +719,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -766,7 +766,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -820,7 +820,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -891,7 +891,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -1087,7 +1087,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( @@ -1146,7 +1146,7 @@ class VaultDataExtensionsTest { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, vaultFilterType = VaultFilterType.AllVaults, hasMasterPassword = true, - restrictItemTypesPolicyOrgIds = null, + restrictItemTypesPolicyOrgIds = emptyList(), ) assertEquals( diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt index 5c6c2c7342..823b900d6f 100644 --- a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/feature/debugmenu/components/FeatureFlagListItems.kt @@ -26,7 +26,6 @@ fun FlagKey.ListItemContent( FlagKey.CipherKeyEncryption, FlagKey.CredentialExchangeProtocolExport, FlagKey.CredentialExchangeProtocolImport, - FlagKey.RemoveCardPolicy, FlagKey.UserManagedPrivilegedApps, -> BooleanFlagItem( label = flagKey.getDisplayLabel(), @@ -72,7 +71,6 @@ private fun FlagKey.getDisplayLabel(): String = when (this) { stringResource(BitwardenString.user_trusted_privileged_app_management) } - FlagKey.RemoveCardPolicy -> stringResource(BitwardenString.remove_card_policy) FlagKey.BitwardenAuthenticationEnabled -> { stringResource(BitwardenString.bitwarden_authentication_enabled) } diff --git a/core/src/main/kotlin/com/bitwarden/core/data/manager/model/FlagKey.kt b/core/src/main/kotlin/com/bitwarden/core/data/manager/model/FlagKey.kt index c2ad8d30f9..43075961a3 100644 --- a/core/src/main/kotlin/com/bitwarden/core/data/manager/model/FlagKey.kt +++ b/core/src/main/kotlin/com/bitwarden/core/data/manager/model/FlagKey.kt @@ -33,7 +33,6 @@ sealed class FlagKey { CredentialExchangeProtocolImport, CredentialExchangeProtocolExport, UserManagedPrivilegedApps, - RemoveCardPolicy, ) } } @@ -72,15 +71,6 @@ sealed class FlagKey { override val defaultValue: Boolean = false } - /** - * Data object holding the feature flag key to enable the removal of card item types. - * This flag will hide card types from organizations with policy enable and individual vaults - */ - data object RemoveCardPolicy : FlagKey() { - override val keyName: String = "pm-16442-remove-card-item-type-policy" - override val defaultValue: Boolean = false - } - /** * Indicates the state of Bitwarden authentication. */ diff --git a/core/src/test/kotlin/com/bitwarden/core/data/manager/model/FlagKeyTest.kt b/core/src/test/kotlin/com/bitwarden/core/data/manager/model/FlagKeyTest.kt index b620912d5a..22a1d17e73 100644 --- a/core/src/test/kotlin/com/bitwarden/core/data/manager/model/FlagKeyTest.kt +++ b/core/src/test/kotlin/com/bitwarden/core/data/manager/model/FlagKeyTest.kt @@ -24,10 +24,6 @@ class FlagKeyTest { FlagKey.UserManagedPrivilegedApps.keyName, "pm-18970-user-managed-privileged-apps", ) - assertEquals( - FlagKey.RemoveCardPolicy.keyName, - "pm-16442-remove-card-item-type-policy", - ) assertEquals( FlagKey.BitwardenAuthenticationEnabled.keyName, "bitwarden-authentication-enabled", @@ -42,7 +38,6 @@ class FlagKeyTest { FlagKey.CredentialExchangeProtocolExport, FlagKey.CipherKeyEncryption, FlagKey.UserManagedPrivilegedApps, - FlagKey.RemoveCardPolicy, FlagKey.BitwardenAuthenticationEnabled, ).all { !it.defaultValue diff --git a/ui/src/main/res/values/strings_non_localized.xml b/ui/src/main/res/values/strings_non_localized.xml index efb1d557ca..36c4d521ed 100644 --- a/ui/src/main/res/values/strings_non_localized.xml +++ b/ui/src/main/res/values/strings_non_localized.xml @@ -22,7 +22,6 @@ Generate error report Error reports User-trusted privileged app management - Remove Card Policy Bitwarden authentication enabled Bitwarden (.json) 2FAS (no password)