Skip to content

[PM-35117] fix: Getting updated values from KDF before displaying update KDF prompt#6802

Merged
aj-rosado merged 4 commits intomainfrom
PM-35117/update-kdf-alert-loop
Apr 16, 2026
Merged

[PM-35117] fix: Getting updated values from KDF before displaying update KDF prompt#6802
aj-rosado merged 4 commits intomainfrom
PM-35117/update-kdf-alert-loop

Conversation

@aj-rosado
Copy link
Copy Markdown
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-35117

📔 Objective

Avoid a loop state where users that updated the KDF information on a different client are stuck with after unlock.
Adding kdf info on state and calling sync to get the most recent data before displaying the prompt

@aj-rosado aj-rosado requested review from a team and david-livefront as code owners April 15, 2026 18:06
@github-actions github-actions Bot added app:password-manager Bitwarden Password Manager app context app:authenticator Bitwarden Authenticator app context labels Apr 15, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

❌ Patch coverage is 85.00000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.65%. Comparing base (7d2bfe1) to head (dd3e84a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ta/auth/repository/util/UserStateJsonExtensions.kt 55.55% 0 Missing and 4 partials ⚠️
...bitwarden/ui/vault/feature/vault/VaultViewModel.kt 93.54% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6802      +/-   ##
==========================================
+ Coverage   85.41%   85.65%   +0.23%     
==========================================
  Files         871      871              
  Lines       60064    60072       +8     
  Branches     8613     8621       +8     
==========================================
+ Hits        51304    51453     +149     
+ Misses       5775     5629     -146     
- Partials     2985     2990       +5     
Flag Coverage Δ
app-data 17.21% <12.50%> (+0.01%) ⬆️
app-ui-auth-tools 20.62% <0.00%> (-0.01%) ⬇️
app-ui-platform 15.63% <0.00%> (+0.35%) ⬆️
app-ui-vault 26.56% <72.50%> (+0.01%) ⬆️
authenticator 6.55% <0.00%> (-0.01%) ⬇️
lib-core-network-bridge 4.28% <0.00%> (-0.01%) ⬇️
lib-data-ui 1.03% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 15, 2026

Logo
Checkmarx One – Scan Summary & Details265c4c2f-3e5e-45fb-84b8-c3fc197e510d

Great job! No new security vulnerabilities introduced in this pull request

* Tracks whether a forced sync was initiated to resolve a KDF update check. While true,
* the KDF update dialog is suppressed until the sync completes.
*/
private var isAwaitingKdfSync = false
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put this in the state

if (authRepository.needsKdfUpdateToMinimums()) {
isAwaitingKdfSync = true
viewModelScope.launch {
try {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a ``tryhere,syncForResult` does not throw anything

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude review tricked me here, it flagged this as necessary in case the syncForResult throws.
Although it should never throw.

}
}

@Suppress("MaxLineLength")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this suppression closer to the offending location.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping on this

verify(exactly = 0) { vaultRepository.syncIfNecessary() }
}

@Suppress("MaxLineLength")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suppression is not needed

),
)
val viewModel = createViewModel()
assertNull(viewModel.stateFlow.value.dialog)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you verify the entire state instead of just the dialog.

assertNull(viewModel.stateFlow.value.dialog)
}

@Suppress("MaxLineLength")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suppression is not needed

runTest {
every { authRepository.needsKdfUpdateToMinimums() } returns true andThen false
val viewModel = createViewModel()
assertNull(viewModel.stateFlow.value.dialog)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing, you should be validating the entire state.

.the_new_recommended_encryption_settings_will_improve_your_account_desc_long
.asText(),
),
viewModel.stateFlow.value.dialog,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

@aj-rosado aj-rosado changed the title Getting updated values from KDF before displaying update KDF prompt [PM-35117] fix: Getting updated values from KDF before displaying update KDF prompt Apr 16, 2026
… tests and removed unnecessary MaxLineLength suppresions
@github-actions github-actions Bot added the t:bug Change Type - Bug label Apr 16, 2026
@aj-rosado aj-rosado added the ai-review-vnext Request a Claude code review using the vNext workflow label Apr 16, 2026
)
}

@Suppress("MaxLineLength")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this closer to the offending line of code

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 16, 2026

Code Review: PM-35117 fix: Getting updated values from KDF before displaying update KDF prompt

PR: #6802 | Author: aj-rosado | Reviewed by: Claude

Summary

This PR fixes a loop state where users who updated their KDF settings on another client would get stuck in a KDF update prompt after unlock. The fix has two parts:

  1. Sync KDF from server: toUpdatedUserStateJson now extracts KDF settings (kdfType, kdfIterations, kdfMemory, kdfParallelism) from the sync response's userDecryption.masterPasswordUnlock.kdf, falling back to existing profile values when not present.

  2. Force sync before showing dialog: VaultViewModel now forces a sync when needsKdfUpdateToMinimums() is true, using an isAwaitingKdfSync flag to suppress the KDF dialog until the sync completes. After sync, it re-checks whether the update is still needed before showing the dialog.

Findings

No issues found. The implementation is clean and well-tested:

  • The isAwaitingKdfSync guard correctly prevents the race condition where getDialogVaultLoaded could show the dialog before the sync response updates local KDF state.
  • The sync-then-recheck pattern in handleKdfSyncCompletedReceive properly handles both outcomes (KDF already updated on server vs. still needs updating).
  • Test coverage includes the key scenarios: forced sync trigger, dialog suppression during sync, dialog shown/hidden based on post-sync state.
  • Test fixtures (createMockUserDecryption, createMockMasterPasswordUnlock) are well-structured for reuse.
  • The default change in createMockSyncResponse (userDecryption = null -> createMockUserDecryption(number)) is reflected in updated test assertions.

Verdict: Approved

@aj-rosado aj-rosado enabled auto-merge April 16, 2026 16:52
@aj-rosado aj-rosado added this pull request to the merge queue Apr 16, 2026
Merged via the queue into main with commit 0143f93 Apr 16, 2026
26 checks passed
@aj-rosado aj-rosado deleted the PM-35117/update-kdf-alert-loop branch April 16, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review-vnext Request a Claude code review using the vNext workflow app:authenticator Bitwarden Authenticator app context app:password-manager Bitwarden Password Manager app context t:bug Change Type - Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants