[PM-24246] Remove restrict-item-deletion-to-can-manage-permission feature flag (#1815)

This commit is contained in:
Matt Czech 2025-07-29 11:11:37 -05:00 committed by GitHub
parent 3f896d0908
commit acd051b8d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 8 additions and 125 deletions

View File

@ -21,11 +21,6 @@ extension FeatureFlag: @retroactive CaseIterable {
/// An SDK flag that enables individual cipher encryption.
static let enableCipherKeyEncryption = FeatureFlag(rawValue: "enableCipherKeyEncryption")
/// A feature flag for the use of new cipher permission properties.
static let restrictCipherItemDeletion = FeatureFlag(
rawValue: "pm-15493-restrict-item-deletion-to-can-manage-permission"
)
/// A feature flag to enable the removal of card item types.
static let removeCardPolicy = FeatureFlag(
rawValue: "pm-16442-remove-card-item-type-policy"
@ -39,7 +34,6 @@ extension FeatureFlag: @retroactive CaseIterable {
.emailVerification,
.enableCipherKeyEncryption,
.removeCardPolicy,
.restrictCipherItemDeletion,
]
}
}

View File

@ -128,7 +128,6 @@ final class AddEditItemProcessor: StateProcessor<// swiftlint:disable:this type_
override func perform(_ effect: AddEditItemEffect) async {
switch effect {
case .appeared:
await loadRestrictItemDeletionFlag()
await showPasswordAutofillAlertIfNeeded()
await checkIfUserHasMasterPassword()
await checkLearnNewLoginActionCardEligibility()
@ -681,14 +680,6 @@ final class AddEditItemProcessor: StateProcessor<// swiftlint:disable:this type_
}
}
/// Load the restrict item deletion flag from the config service to state.
///
func loadRestrictItemDeletionFlag() async {
state.restrictCipherItemDeletionFlagEnabled = await services.configService.getFeatureFlag(
.restrictCipherItemDeletion
)
}
/// Shows the password autofill information alert if it hasn't been shown before and the user
/// is adding a new login in the app.
///

View File

@ -800,14 +800,6 @@ class AddEditItemProcessorTests: BitwardenTestCase {
XCTAssertFalse(subject.state.showMasterPasswordReprompt)
}
/// `perform(_:)` with `.appeared` checks restrictCipherItemDeletionFlag and sets value to state.
@MainActor
func test_perform_appeared_loadRestrictItemDeletionFlag() async {
configService.featureFlagsBool[.restrictCipherItemDeletion] = true
await subject.perform(.appeared)
XCTAssertTrue(subject.state.restrictCipherItemDeletionFlagEnabled)
}
/// `perform` with `.checkPasswordPressed` checks the password with the HIBP service.
@MainActor
func test_perform_checkPasswordPressed_exposedPassword() async throws {

View File

@ -97,9 +97,6 @@ protocol AddEditItemState: Sendable {
/// A computed property that indicates if we should show the learn new login action card.
var shouldShowLearnNewLoginActionCard: Bool { get }
/// A flag indicating if cipher permissions should be used.
var restrictCipherItemDeletionFlagEnabled: Bool { get set }
/// The SSH key item state.
var sshKeyState: SSHKeyItemState { get set }

View File

@ -110,9 +110,6 @@ struct CipherItemState: Equatable { // swiftlint:disable:this type_body_length
/// The list of ownership options that can be selected for the cipher.
var ownershipOptions: [CipherOwner]
/// A flag indicating if cipher permissions should be used.
var restrictCipherItemDeletionFlag: Bool = false
/// If master password reprompt toggle should be shown
var showMasterPasswordReprompt: Bool
@ -157,7 +154,7 @@ struct CipherItemState: Equatable { // swiftlint:disable:this type_body_length
/// Whether or not this item can be deleted by the user.
var canBeDeleted: Bool {
// backwards compatibility for old server versions
guard restrictCipherItemDeletionFlagEnabled, let cipherPermissions = cipher.permissions else {
guard let cipherPermissions = cipher.permissions else {
guard !collectionIds.isEmpty else { return true }
return allUserCollections.contains { collection in
guard let id = collection.id else { return false }
@ -172,7 +169,7 @@ struct CipherItemState: Equatable { // swiftlint:disable:this type_body_length
/// Whether or not this item can be restored by the user.
var canBeRestored: Bool {
// backwards compatibility for old server versions
guard restrictCipherItemDeletionFlagEnabled, let cipherPermissions = cipher.permissions else {
guard let cipherPermissions = cipher.permissions else {
return isSoftDeleted
}
@ -245,11 +242,6 @@ struct CipherItemState: Equatable { // swiftlint:disable:this type_body_length
}
}
var restrictCipherItemDeletionFlagEnabled: Bool {
get { restrictCipherItemDeletionFlag }
set { restrictCipherItemDeletionFlag = newValue }
}
/// The flag indicating if we should show the learn new login action card.
var shouldShowLearnNewLoginActionCard: Bool {
isLearnNewLoginActionCardEligible && configuration == .add && type == .login

View File

@ -153,8 +153,7 @@ class CipherItemStateTests: BitwardenTestCase { // swiftlint:disable:this type_b
restore: true
)
)
var state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
state.restrictCipherItemDeletionFlagEnabled = true
let state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
XCTAssertFalse(state.canBeDeleted)
}
@ -167,7 +166,6 @@ class CipherItemStateTests: BitwardenTestCase { // swiftlint:disable:this type_b
permissions: nil
)
var state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
state.restrictCipherItemDeletionFlagEnabled = true
XCTAssertFalse(state.canBeRestored)
cipher = CipherView.loginFixture(
@ -191,8 +189,7 @@ class CipherItemStateTests: BitwardenTestCase { // swiftlint:disable:this type_b
restore: true
)
)
var state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
state.restrictCipherItemDeletionFlagEnabled = true
let state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
XCTAssertTrue(state.canBeRestored)
}
@ -207,8 +204,7 @@ class CipherItemStateTests: BitwardenTestCase { // swiftlint:disable:this type_b
restore: false
)
)
var state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
state.restrictCipherItemDeletionFlagEnabled = true
let state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
XCTAssertFalse(state.canBeRestored)
}
@ -247,22 +243,6 @@ class CipherItemStateTests: BitwardenTestCase { // swiftlint:disable:this type_b
XCTAssertFalse(state.hasOrganizations)
}
/// `restrictCipherItemDeletionFlagEnable` default value is false
func test_restrictCipherItemDeletionFlagValue() throws {
let cipher = CipherView.loginFixture(
login: .fixture(),
permissions: CipherPermissions(
delete: false,
restore: true
)
)
var state = try XCTUnwrap(CipherItemState(existing: cipher, hasPremium: true))
XCTAssertFalse(state.restrictCipherItemDeletionFlagEnabled)
state.restrictCipherItemDeletionFlagEnabled = true
XCTAssertTrue(state.restrictCipherItemDeletionFlagEnabled)
}
/// `getter:icon` returns the icon for a card cipher with a known brand.
func test_icon_cardKnownBrand() throws {
let cipher = CipherView.cardFixture(card: .fixture(brand: "Visa"))
@ -401,4 +381,4 @@ class CipherItemStateTests: BitwardenTestCase { // swiftlint:disable:this type_b
state.isLearnNewLoginActionCardEligible = false
XCTAssertFalse(state.shouldShowLearnNewLoginActionCard)
}
} // swiftlint:disable:this file_length
}

View File

@ -505,9 +505,6 @@ private extension ViewItemProcessor {
}
let showWebIcons = await services.stateService.getShowWebIcons()
let restrictCipherItemDeletionFlagEnabled: Bool = await services.configService.getFeatureFlag(
.restrictCipherItemDeletion
)
var totpState = LoginTOTPState(cipher.login?.totp)
if let key = totpState.authKeyModel,
let updatedState = try? await services.vaultRepository.refreshTOTPCode(for: key) {
@ -517,8 +514,7 @@ private extension ViewItemProcessor {
guard var newState = ViewItemState(
cipherView: cipher,
hasPremium: hasPremium,
iconBaseURL: services.environmentService.iconsURL,
restrictCipherItemDeletionFlagEnabled: restrictCipherItemDeletionFlagEnabled
iconBaseURL: services.environmentService.iconsURL
) else { continue }
if case var .data(itemState) = newState.loadingState {

View File

@ -175,7 +175,6 @@ class ViewItemProcessorTests: BitwardenTestCase { // swiftlint:disable:this type
XCTAssertNotNil(subject.streamCipherDetailsTask)
XCTAssertTrue(subject.state.hasPremiumFeatures)
XCTAssertFalse(subject.state.restrictCipherItemDeletionFlagEnabled)
XCTAssertFalse(vaultRepository.fetchSyncCalled)
XCTAssertEqual(subject.state.loadingState, .data(expectedState))
@ -411,25 +410,6 @@ class ViewItemProcessorTests: BitwardenTestCase { // swiftlint:disable:this type
XCTAssertFalse(vaultRepository.fetchSyncCalled)
}
/// `perform(_:)` with `.appeared` loads feature flag value for .restrictCipherItemDeletion.
@MainActor
func test_perform_appeared_restrictItemDeletion() {
let account = Account.fixture()
stateService.activeAccount = account
configService.featureFlagsBool = [
.restrictCipherItemDeletion: true,
]
let task = Task {
await subject.perform(.appeared)
}
waitFor(subject.state.loadingState != .loading(nil))
task.cancel()
XCTAssertTrue(subject.state.restrictCipherItemDeletionFlagEnabled)
}
/// `perform` with `.checkPasswordPressed` records any errors.
@MainActor
func test_perform_checkPasswordPressed_error() async throws {

View File

@ -45,9 +45,6 @@ struct ViewItemState: Equatable, Sendable {
/// The password history of the item.
var passwordHistory: [PasswordHistoryView]?
/// A flag indicating if cipher permissions should be used.
var restrictCipherItemDeletionFlagEnabled = false
/// A toast message to show in the view.
var toast: Toast?
}
@ -65,18 +62,15 @@ extension ViewItemState {
init?(
cipherView: CipherView,
hasPremium: Bool,
iconBaseURL: URL?,
restrictCipherItemDeletionFlagEnabled: Bool
iconBaseURL: URL?
) {
guard var cipherItemState = CipherItemState(
existing: cipherView,
hasPremium: hasPremium,
iconBaseURL: iconBaseURL
) else { return nil }
cipherItemState.restrictCipherItemDeletionFlagEnabled = restrictCipherItemDeletionFlagEnabled
self.init(loadingState: .data(cipherItemState))
hasPremiumFeatures = cipherItemState.accountHasPremium
passwordHistory = cipherView.passwordHistory
self.restrictCipherItemDeletionFlagEnabled = restrictCipherItemDeletionFlagEnabled
}
}

View File

@ -90,37 +90,4 @@ class ViewItemStateTests: BitwardenTestCase {
let subject = ViewItemState()
XCTAssertEqual(subject.navigationTitle, "")
}
/// `restrictCipherItemDeletionFlagEnabled` default value is false.
func test_restrictCipherItemDeletionFlagEnabled() {
let subject = ViewItemState(
loadingState: .data(
CipherItemState(
existing: .fixture(
id: "id",
reprompt: .password
),
hasPremium: true
)!
)
)
XCTAssertFalse(subject.restrictCipherItemDeletionFlagEnabled)
}
/// `restrictCipherItemDeletionFlagEnabled` is correctly initialized.
func test_restrictCipherItemDeletionFlagEnabled_value() {
let subject = ViewItemState(
loadingState: .data(
CipherItemState(
existing: .fixture(
id: "id",
reprompt: .password
),
hasPremium: true
)!
),
restrictCipherItemDeletionFlagEnabled: true
)
XCTAssertTrue(subject.restrictCipherItemDeletionFlagEnabled)
}
}