Skip to content

[PM-39454] feat(km): add repository methods to set the user key id - #8109

Draft
quexten wants to merge 3 commits into
km/user-key-id-03-userkeyid-columnfrom
km/user-key-id-04-repository-methods
Draft

[PM-39454] feat(km): add repository methods to set the user key id#8109
quexten wants to merge 3 commits into
km/user-key-id-03-userkeyid-columnfrom
km/user-key-id-04-repository-methods

Conversation

@quexten

@quexten quexten commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Adds methods to set the user-key id on the user table. There is two functions, one to set the id in all cases, and one to set it if not present yet. We do not want to accidentally overwrite it, but in some cases (key rotations) we must overwrite it.

@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.36364% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.38%. Comparing base (b17a1f0) to head (5c08749).

Files with missing lines Patch % Lines
src/Core/Services/Implementations/UserService.cs 55.55% 3 Missing and 1 partial ⚠️
...Management/Models/Data/MasterPasswordUnlockData.cs 60.00% 2 Missing ⚠️
...ure.EntityFramework/Repositories/UserRepository.cs 93.10% 2 Missing ⚠️
...re/KeyManagement/Models/Data/RegisterFinishData.cs 66.66% 1 Missing ⚠️
Additional details and impacted files
@@                          Coverage Diff                           @@
##           km/user-key-id-03-userkeyid-column    #8109      +/-   ##
======================================================================
+ Coverage                               67.37%   67.38%   +0.01%     
======================================================================
  Files                                    2303     2303              
  Lines                                  100288   100349      +61     
  Branches                                 9032     9034       +2     
======================================================================
+ Hits                                    67569    67622      +53     
- Misses                                  30438    30445       +7     
- Partials                                 2281     2282       +1     

☔ View full report in Codecov by Harness.
📢 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@quexten
quexten force-pushed the km/user-key-id-04-repository-methods branch from 2d23b7d to bc1d5cc Compare July 31, 2026 13:33
@quexten quexten added ai-review Request a Claude code review t:feature Change Type - Feature Development labels Jul 31, 2026
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed 5c087491c, focusing on what the latest fixup! changed relative to the previously reviewed 49ae54403. That fixup only touches UserService.CreateUserAsync(User, RegisterFinishData): the V2 register-finish path now builds a List<UpdateUserData> and appends SetUserKeyId only when registerFinishData.UserKeyId is not null, which resolves the NullReferenceException flagged in the open thread — no request model populates UserKeyId today, so the delegate is simply never composed and nothing dereferences null inside the transaction. The rest of the change re-verified clean: @UserKeyId VARCHAR(32) matches [User].[UserKeyId] in both new procedures and their SSDT copies, the [UserKeyId] IS NULL predicate plus the EF ExecuteUpdateAsync translation keep the backfill atomic across all four providers, and the two TestUserTracking repositories inherit from the concrete repositories so the two new IUserRepository members are not a breaking change.

Code Review Details

No findings at or above the reporting threshold.

Verified during this pass, no action needed:

  • The open ❌ thread on src/Core/Services/Implementations/UserService.cs is addressed. SetUserKeyId(Guid, KeyId) is now only reached when the client supplied a key id; RegisterFinishRequestModel.ToData(), MasterPasswordUnlockDataRequestModel.ToData(), and MasterPasswordUnlockAndAuthenticationDataModel.ToMasterPasswordUnlockData() still leave it unset, so the branch is inert until the client wiring lands. List<UpdateUserData> resolves via the existing using Bit.Core.Repositories;.
  • Adding UserKeyId to MasterPasswordUnlockData.Equals/GetHashCode and RegisterFinishData.Equals/GetHashCode is safe: no production code compares two instances of either type, and the d.MasterPasswordUnlock == unlockData assertions in tests are reference comparisons (neither type overloads ==). KeyId overrides Equals/GetHashCode consistently and its == delegates to the static Equals(KeyId?, KeyId?), so HashCode.Combine and the null cases behave.
  • Provider parity on revision dates: neither User_SetUserKeyId nor the EF SetUserKeyId bumps AccountRevisionDate, and on the only caller SetV2AccountCryptographicStateAsync bumps it in the same transaction.
  • Dapper TrySetUserKeyIdAsync reads SELECT @@ROWCOUNT under SET NOCOUNT ON, so ExecuteScalarAsync<int> receives the row count. The EF equivalent's DateTime.UtcNow inside SetProperty translates on SQL Server, Postgres, MySQL, and SQLite.
  • Migration ordering (2026-08-01_00) follows the two 2026-07-31_* scripts in the base branch, the new procedures are picked up by the globbing Sql.sqlproj, and no schema change means no EF migrations are required.

Noted, not worth a thread: MasterPasswordUnlockData.ContainedKeyId() and the UserKeyId members on KeyConnectorKeysData / BaseRotateUserAccountKeysData still have no callers, and MasterPasswordUnlockData.UserKeyId remains write-only for every provider — the description attributes this to the next branch in the stack.

Comment thread util/Migrator/DbScripts/2026-08-01_00_UserKeyIdProcedures.sql Outdated
Comment thread src/Infrastructure.Dapper/Repositories/UserRepository.cs Outdated
@quexten
quexten force-pushed the km/user-key-id-04-repository-methods branch from bc1d5cc to c5ba4f6 Compare July 31, 2026 13:59
@quexten
quexten marked this pull request as ready for review July 31, 2026 15:14
@quexten
quexten requested review from a team as code owners July 31, 2026 15:14
@quexten
quexten requested a review from eligrubb July 31, 2026 15:14
Two ways to write the key id, for two different situations.

SetUserKeyId overwrites unconditionally and returns a deferred UpdateUserData delegate, so
the write joins the transaction that establishes the user key itself. There the supplied
key id is authoritative and whatever was stored before is stale by definition.

TrySetUserKeyIdAsync only writes when the column is still null, reporting whether it
stored anything. That is the backfill case: an existing account whose key id the server
never learned, where a client's claim must not overwrite a value some other flow already
established.

Also carries the key id on the Core data models the repositories read from —
MasterPasswordUnlockData, RegisterFinishData and KeyConnectorKeysData — and moves
User_UpdateMasterPassword and User_UpdateMasterPasswordUnlockData here from the schema
commit so that each procedure lands with the caller that supplies its parameter.

SetMasterPassword applies its key id fill-only, since setting a master password re-wraps
the existing user key rather than replacing it: it records a key id the account does not
have yet, but never renames one it already has. The COALESCE in User_UpdateMasterPassword
and the ??= in the EF path are the same rule, so all four providers agree.

Nothing calls these yet; the flows that do come next.
@quexten
quexten requested a review from a team as a code owner July 31, 2026 15:20
@quexten
quexten requested a review from JimmyVo16 July 31, 2026 15:20
@quexten
quexten force-pushed the km/user-key-id-04-repository-methods branch from c5ba4f6 to 9202a9c Compare July 31, 2026 15:20
@quexten
quexten marked this pull request as draft July 31, 2026 16:17
Comment thread src/Core/Services/Implementations/UserService.cs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant