Skip to content

[PM-19232] Implement externalId handling in PatchUserCommand with validation#6998

Merged
JaredScar merged 10 commits intomainfrom
ac/pm-19232-entraID-reports-successful-PATCH-ops-fix
Feb 26, 2026
Merged

[PM-19232] Implement externalId handling in PatchUserCommand with validation#6998
JaredScar merged 10 commits intomainfrom
ac/pm-19232-entraID-reports-successful-PATCH-ops-fix

Conversation

@JaredScar
Copy link
Copy Markdown
Contributor

🎟️ Tracking

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

📔 Objective

Fit EntraID handling

@JaredScar JaredScar requested a review from a team as a code owner February 12, 2026 19:38
@JaredScar JaredScar requested a review from JimmyVo16 February 12, 2026 19:38
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 12, 2026

Logo
Checkmarx One – Scan Summary & Details97631eec-c25f-410b-b07b-d7e62a2c938f

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

@JaredScar JaredScar added the ai-review Request a Claude code review label Feb 12, 2026
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 12, 2026

Claude finished @JaredScar's task in 5m 5s —— View job


Re-Review: PR #6998 - PM-19232 Implement externalId handling in PatchUserCommand with validation

Reviewed commits since last review: df7935f15, c61e31bda, 8651cb38e, 4a764e9c1

Previous Findings Status

Finding Severity Status
Stale state on restore + externalId combined operation CRITICAL Fixed in 8651cb38e -- re-fetch added after active operations
Missing indentation on closing brace IMPORTANT Fixed in c61e31bda
Missing test for combined value object SUGGESTED Addressed -- PatchUser_ActiveAndExternalIdFromValue_Success and PatchUser_RestoreAndExternalIdFromValue_DoesNotRevertRestore added

New Changes Analysis

The latest commits correctly address all previously identified issues:

  1. Re-fetch logic (PatchUserCommand.cs lines 53-58, 77-82): After HandleActiveOperationAsync returns true, the entity is re-fetched from the repository. This prevents ReplaceAsync from overwriting database state with stale in-memory values. The fix is applied in both the path-based active branch and the value-object active branch.

  2. Test coverage (PatchUserCommandTests.cs lines 386-467): Two new tests verify the combined active + externalId scenario. The restore test (PatchUser_RestoreAndExternalIdFromValue_DoesNotRevertRestore) specifically validates that the re-fetched entity has non-revoked status, which would have caught the original bug.

Verdict

No new issues found. All previously identified issues have been resolved. The PR is in good shape.

Overall: Approve -- The implementation correctly handles externalId SCIM PATCH operations with proper validation (length, uniqueness), supports both path-based and value-object formats, and handles combined operations safely with the re-fetch pattern.

Comment thread bitwarden_license/src/Scim/Users/PatchUserCommand.cs
{
// Replace operations
if (operation.Op?.ToLowerInvariant() == "replace")
if (operation.Op?.ToLowerInvariant() == PatchOps.Replace)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Non-blocker: I know you're just following the existing pattern, so the code as is good, but consider abstracting this logic into its own method and using the early return pattern to reduce nested conditionals when possible.

            // Replace operations
            if (operation.Op?.ToLowerInvariant() == PatchOps.Replace)
            {
                // Active from path
                if (operation.Path?.ToLowerInvariant() == "active")
                {
                    var active = operation.Value.ToString()?.ToLowerInvariant();
                    var handled = await HandleActiveOperationAsync(orgUser, active == "true");
                    if (!operationHandled)
                    {
                        operationHandled = handled;
                    }
                }
                // Active from value object
                else if (string.IsNullOrWhiteSpace(operation.Path) &&
                    operation.Value.TryGetProperty("active", out var activeProperty))
                {
                    var handled = await HandleActiveOperationAsync(orgUser, activeProperty.GetBoolean());
                    if (!operationHandled)
                    {
                        operationHandled = handled;
                    }
                }
                // ExternalId from path
                else if (operation.Path?.ToLowerInvariant() == PatchPaths.ExternalId)
                {
                    var newExternalId = operation.Value.GetString();
                    await HandleExternalIdOperationAsync(orgUser, newExternalId);
                    operationHandled = true;
                }
                // ExternalId from value object
                else if (string.IsNullOrWhiteSpace(operation.Path) &&
                    operation.Value.TryGetProperty("externalId", out var externalIdProperty))
                {
                    var newExternalId = externalIdProperty.GetString();
                    await HandleExternalIdOperationAsync(orgUser, newExternalId);
                    operationHandled = true;
                }
            }

Methods are normally used for DRY, but I think the ability to keep the scope small and let the method’s name provide a quick summary of what this group of code is doing makes it easier to understand at a glance. Also, the early return pattern makes it easier to follow.

JimmyVo16
JimmyVo16 previously approved these changes Feb 13, 2026
Copy link
Copy Markdown
Contributor

@JimmyVo16 JimmyVo16 left a comment

Choose a reason for hiding this comment

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

Ping me again when you need a reapproval after fixing the tests.

Comment thread bitwarden_license/test/Scim.Test/Users/PatchUserCommandTests.cs Outdated
…ported operations instead of throwing exceptions. Update method names for clarity and adjust assertions in test cases accordingly.
Comment thread bitwarden_license/src/Scim/Users/PatchUserCommand.cs
@JaredScar JaredScar requested a review from JimmyVo16 February 13, 2026 20:49
JimmyVo16
JimmyVo16 previously approved these changes Feb 13, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 93.47826% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.69%. Comparing base (25df3c3) to head (4a764e9).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...twarden_license/src/Scim/Users/PatchUserCommand.cs 93.47% 0 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6998      +/-   ##
==========================================
+ Coverage   56.67%   56.69%   +0.01%     
==========================================
  Files        2013     2013              
  Lines       88131    88171      +40     
  Branches     7846     7856      +10     
==========================================
+ Hits        49949    49987      +38     
- Misses      36362    36363       +1     
- Partials     1820     1821       +1     

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

…alId properties from value objects, consolidating logic for improved clarity and maintainability.
Comment thread bitwarden_license/test/Scim.Test/Users/PatchUserCommandTests.cs
Copy link
Copy Markdown
Contributor

@JimmyVo16 JimmyVo16 left a comment

Choose a reason for hiding this comment

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

The code is approved, but please make sure to add test coverage for all paths since it’s a complex method with many nested conditions.

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Comment thread bitwarden_license/test/Scim.Test/Users/PatchUserCommandTests.cs Outdated
JimmyVo16
JimmyVo16 previously approved these changes Feb 26, 2026
…e characters and ensuring proper code structure.
Comment thread bitwarden_license/src/Scim/Users/PatchUserCommand.cs
… operations, ensuring accurate updates. Add corresponding test case to verify behavior when restoring users and updating externalId.
@sonarqubecloud
Copy link
Copy Markdown

@JaredScar JaredScar merged commit d17d43c into main Feb 26, 2026
43 checks passed
@JaredScar JaredScar deleted the ac/pm-19232-entraID-reports-successful-PATCH-ops-fix branch February 26, 2026 22:44
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants