Skip to content

Conversation

@r-tome
Copy link
Contributor

@r-tome r-tome commented Dec 2, 2025

🎟️ Tracking

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

📔 Objective

Adds BulkResendOrganizationInvitesCommand to improve bulk reinvite performance by reusing the existing SendOrganizationInvitesCommand for batched sending.

The new path is behind the IncreaseBulkReinviteLimitForCloud feature flag.

With the flag enabled, reinviting 8,000 users dropped from ~36,719ms to ~1,400ms in a local development environment, roughly a 26× improvement.

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

- Added IBulkResendOrganizationInvitesCommand interface to define the bulk resend operation.
- Created BulkResendOrganizationInvitesCommand class to handle the logic for resending invites to multiple organization users.
- Integrated logging and validation to ensure only valid users receive invites.
- Included error handling for non-existent organizations and invalid user statuses.
- Implemented comprehensive test cases for the BulkResendOrganizationInvitesCommand class.
- Validated user statuses and ensured correct handling of valid and invalid users during bulk invite resends.
- Included tests for scenarios such as organization not found and empty user lists.
- Utilized Xunit and NSubstitute for effective testing and mocking of dependencies.
- Registered IBulkResendOrganizationInvitesCommand in the service collection for dependency injection.
…InvitesCommand

- Added IBulkResendOrganizationInvitesCommand to the OrganizationUsersController for handling bulk invite resends based on feature flag.
- Updated BulkReinvite method to conditionally use the new command or the legacy service based on the feature flag status.
- Enhanced unit tests to verify correct command usage depending on feature flag state, ensuring robust testing for both scenarios.
@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

Logo
Checkmarx One – Scan Summary & Details21173959-840c-47c6-9aee-b40c0ec1da7f

New Issues (2)

Checkmarx found the following issues in this Pull Request

Severity Issue Source File / Package Checkmarx Insight
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1519
detailsMethod at line 1519 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
ID: dMGF5qNfAN72zlvQcA1MgbhHv%2Fc%3D
Attack Vector
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1395
detailsMethod at line 1395 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
ID: iOCFr11iI9znjDnv46yLfiS4aDY%3D
Attack Vector
Fixed Issues (5)

Great job! The following issues were fixed in this Pull Request

Severity Issue Source File / Package
MEDIUM CSRF /src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 489
MEDIUM CSRF /src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 97
MEDIUM CSRF /bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs: 87
MEDIUM CSRF /bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs: 97
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 300

@r-tome r-tome marked this pull request as ready for review December 2, 2025 16:26
@r-tome r-tome requested a review from a team as a code owner December 2, 2025 16:26
@r-tome r-tome requested a review from BTreston December 2, 2025 16:26
@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

@codecov
Copy link

codecov bot commented Dec 2, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.48%. Comparing base (18a8829) to head (b07de14).
⚠️ Report is 9 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6670      +/-   ##
==========================================
- Coverage   57.27%   53.48%   -3.80%     
==========================================
  Files        1917     1918       +1     
  Lines       85518    85565      +47     
  Branches     7673     7678       +5     
==========================================
- Hits        48983    45764    -3219     
- Misses      34691    38030    +3339     
+ Partials     1844     1771      -73     

☔ 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.

@claude
Copy link
Contributor

claude bot commented Dec 5, 2025

Claude finished @r-tome's task —— View job


Code Review Complete

I've reviewed the PR that adds BulkResendOrganizationInvitesCommand to optimize bulk reinvite performance. Overall, this is a well-implemented optimization with excellent test coverage. Here are my findings:


👍 Strengths

  1. Excellent Performance Improvement: The ~26× performance boost (from 36.7s to 1.4s for 8,000 users) is impressive and addresses a real scalability concern.

  2. Well-Tested: Comprehensive unit tests cover all scenarios:

    • Valid and invalid users
    • Empty lists
    • Organization not found
    • Controller feature flag toggling
  3. Clean Architecture: The new command follows the existing command pattern and properly reuses SendOrganizationInvitesCommand for batched processing.

  4. Feature Flag Protection: Changes are properly gated behind IncreaseBulkReinviteLimitForCloud, allowing safe rollout.

  5. Proper Dependency Injection: Correctly registered in OrganizationServiceCollectionExtensions.cs:200.


🎨 Suggestions for Improvement

1. Parameter Naming Inconsistency (Minor)

Location: src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/IBulkResendOrganizationInvitesCommand.cs:12-17

The parameter is named organizationUsersId (singular "Id") but should be plural since it's a collection:

// Current
IEnumerable<Guid> organizationUsersId

// Suggested
IEnumerable<Guid> organizationUserIds

This applies to:

  • Interface: IBulkResendOrganizationInvitesCommand.cs:17
  • Implementation: BulkResendOrganizationInvitesCommand.cs:33

2. Unused Parameter (Minor)

Location: src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/BulkResendOrganizationInvitesCommand.cs:32

The invitingUserId parameter is accepted but never used. Consider:

  • If it's needed for future logging/auditing, add a TODO comment
  • If not needed, consider removing it (though this matches the legacy signature)
  • If it should be logged, implement it now

Current code:

public async Task<IEnumerable<Tuple<OrganizationUser, string>>> BulkResendInvitesAsync(
    Guid organizationId,
    Guid? invitingUserId,  // ← Never used
    IEnumerable<Guid> organizationUsersId)

3. Logging Diagnostics (Question)

Location: src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/BulkResendOrganizationInvitesCommand.cs:36

_logger.LogUserInviteStateDiagnostics(orgUsers);
  • ❓ What does this log extension method do? Ensure it doesn't log PII or sensitive data (per CLAUDE.md security requirements).
  • If this is diagnostic logging for troubleshooting, consider if it should be gated by a log level or removed in production.

ℹ️ Architecture Questions

4. Error Handling Strategy

Location: src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/BulkResendOrganizationInvitesCommand.cs:47-56

The command filters invalid users and returns them with error messages, while valid users proceed to send invites. This is good, but consider:

  • What happens if SendInvitesAsync throws an exception for some users?
  • Should partial failures be handled more granularly?
  • The legacy OrganizationService.ResendInvitesAsync might have different error handling - ensure behavior parity.

5. Performance Implications of GetManyAsync

Location: src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/BulkResendOrganizationInvitesCommand.cs:35

var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUsersId);

For 8,000+ users:

  • Does GetManyAsync handle large collections efficiently?
  • Consider if there's a batch size limit or if this query could time out.
  • The performance improvement suggests this is fine, but document any assumptions about maximum batch sizes.

✅ Security Review

No security concerns identified. The implementation:

  • Maintains zero-knowledge principles (no vault data access)
  • Uses existing validated command for actual email sending
  • Validates organization membership and status before processing
  • Does not expose sensitive data in responses (only user IDs and generic error messages)

♻️ Consider for Future Improvements

  1. Batching within BulkResendInvitesCommand: If SendInvitesAsync could be further optimized by sending in sub-batches (e.g., 500 at a time), consider implementing that.

  2. Telemetry: Consider adding metrics for:

    • Batch size
    • Success/failure rates
    • Execution time
      This would help monitor the performance improvement in production.
  3. Feature Flag Cleanup: Once the feature flag is enabled everywhere, consider removing the legacy code path in OrganizationUsersController.cs:276-292 to reduce technical debt.


📝 Test Coverage Notes

The test coverage is excellent. The controller tests properly verify:

  • Feature flag toggling (OrganizationUsersControllerTests.cs:737-797)
  • Both code paths are exercised
  • The new command is called with correct parameters

The command tests cover:

  • Valid/invalid user filtering (BulkResendOrganizationInvitesCommandTests.cs:20-55)
  • Empty lists (BulkResendOrganizationInvitesCommandTests.cs:97-112)
  • Organization not found (BulkResendOrganizationInvitesCommandTests.cs:82-95)

Summary

This is a solid implementation that delivers significant performance improvements while maintaining code quality and test coverage. The suggestions above are mostly minor improvements that don't block merging.

Recommendation: ✅ Approve with minor suggestions for consideration.

The most important items to address:

  1. Rename organizationUsersIdorganizationUserIds for consistency
  2. Clarify the purpose of invitingUserId parameter
  3. Verify the logging diagnostics don't expose PII

@r-tome r-tome merged commit 5469d8b into main Dec 5, 2025
41 of 42 checks passed
@r-tome r-tome deleted the ac/pm-28260/optimize-bulk-reinvite-endpoint branch December 5, 2025 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants