Skip to content

Conversation

@jrmccannon
Copy link
Contributor

@jrmccannon jrmccannon commented Oct 23, 2025

🎟️ Tracking

PM-26636

📔 Objective

TODO

📸 Screenshots

⏰ 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

@github-actions
Copy link
Contributor

github-actions bot commented Oct 23, 2025

Logo
Checkmarx One – Scan Summary & Detailsc84838ae-1410-44f3-b616-ed8d0c0bd9f4

Fixed Issues (2)

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

Severity Issue Source File / Package
MEDIUM CSRF /src/Api/Dirt/Controllers/OrganizationReportsController.cs: 173
MEDIUM CSRF /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 72


if (userId is null || userId.Value == Guid.Empty)
{
throw new UnauthorizedAccessException();
Copy link
Contributor

Choose a reason for hiding this comment

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

Could possibly be an attribute? Just something to think about



[Authorize<ManageUsersRequirement>]
[HttpPost("{id:guid}/auto-confirm")]
Copy link
Contributor

Choose a reason for hiding this comment

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

switch (result.AsError)
{
case OrganizationNotFound organizationNotFound:
throw new NotFoundException(organizationNotFound.Message);
Copy link
Contributor

Choose a reason for hiding this comment

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

How does the return message look like?

errorMessage = "Resource not found.";

Should we throw an exception on the controller or return NotFound()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah. I see now. Well that's not great.

Should we allow for the overriding of that not found message? Or is that something that needs to be run by architecture?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think its wise to run by architecture

@codecov
Copy link

codecov bot commented Oct 28, 2025

Codecov Report

❌ Patch coverage is 0% with 249 lines in your changes missing coverage. Please review.
✅ Project coverage is 13.24%. Comparing base (5f0e038) to head (031c080).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
...ser/AutomaticallyConfirmOrganizationUserCommand.cs 0.00% 124 Missing ⚠️
.../AutomaticallyConfirmOrganizationUsersValidator.cs 0.00% 68 Missing ⚠️
...ser/AutomaticallyConfirmOrganizationUserRequest.cs 0.00% 15 Missing ⚠️
...AdminConsole/Utilities/v2/Results/CommandResult.cs 0.00% 13 Missing ⚠️
...atures/OrganizationUsers/AutoConfirmUser/Errors.cs 0.00% 12 Missing ⚠️
...equirements/SingleOrganizationPolicyRequirement.cs 0.00% 5 Missing ⚠️
...onsole/Utilities/v2/Validation/ValidationResult.cs 0.00% 5 Missing ⚠️
src/Core/AdminConsole/Utilities/v2/Errors.cs 0.00% 4 Missing ⚠️
...eatures/OrganizationServiceCollectionExtensions.cs 0.00% 2 Missing ⚠️
...ures/Policies/PolicyServiceCollectionExtensions.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #6488       +/-   ##
===========================================
- Coverage   51.86%   13.24%   -38.62%     
===========================================
  Files        1901     1141      -760     
  Lines       84051    49886    -34165     
  Branches     7501     3888     -3613     
===========================================
- Hits        43594     6608    -36986     
- Misses      38763    43158     +4395     
+ Partials     1694      120     -1574     

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

@eliykat eliykat self-requested a review October 29, 2025 05:23
[FromRoute] Guid id,
[FromBody] OrganizationUserConfirmRequestModel model)
{
if (!_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be replaced with [RequireFeature(FeatureFlagKeys.AutomaticConfirmUsers)]


var successfulConfirmation = await organizationUserRepository.ConfirmOrganizationUserAsync(validatedRequest.OrganizationUser);

if (!successfulConfirmation) return new None();
Copy link
Contributor

Choose a reason for hiding this comment

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

I would add a comment here to explain that the only reason this would not be successful is if the user is already confirmed. Otherwise it seems like silent failure.

Copy link
Member

Choose a reason for hiding this comment

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

I think it's also worth explaining here that this is idempotent and designed to handle multiple simultaneous requests from logged in clients.

{
try
{
if (!featureService.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
Copy link
Contributor

Choose a reason for hiding this comment

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

Extract all these conditions into a private method

Copy link
Contributor

Choose a reason for hiding this comment

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

Filename is misspelled


if (result is { IsError: true })
{
return result.AsError switch
Copy link
Contributor

Choose a reason for hiding this comment

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

The Billing team has a helper method in BaseBillingController.Handle, we should do something similar

Copy link
Contributor

Choose a reason for hiding this comment

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

We should add unit tests for this command

Copy link
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

Nice work!

Comment on lines +6 to +8
/// <summary>
/// Command to automatically confirm an organization user.
/// </summary>
Copy link
Member

Choose a reason for hiding this comment

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

More context around what autoconfirm is would be helpful - <remarks> is good for this. e.g.

The autoconfirm feature sends push notifications to eligible logged in client apps to automatically confirm OrganizationUsers without manual intervention by administrators. When a client app receives the push notification, it performs the key exchange and sends an autoconfirm request to the server. This command is used to process those requests. It should not be used to confirm users in any other context.

I think a README in the AutoConfirmUser folder would also be useful to document the feature in more detail. I'll raise it in the dev channel.

{
var requestData = await RetrieveDataAsync(request);

if (requestData.IsError) return requestData.AsError;
Copy link
Member

Choose a reason for hiding this comment

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

Here, I got you these: { and }

(Please avoid single line if statements.)

Comment on lines +70 to +82
await collectionRepository.CreateAsync(
new Collection
{
OrganizationId = request.Organization.Id,
Name = request.DefaultUserCollectionName,
Type = CollectionType.DefaultUserCollection
},
groups: null,
[new CollectionAccessSelection
{
Id = request.OrganizationUser.Id,
Manage = true
}]);
Copy link
Member

Choose a reason for hiding this comment

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

💭 (non-blocking) Thoughts on making this an idempotent repository method as well? e.g. CreateDefaultCollectionAsync. Given that we are creating it in multiple places and creating default collections properly is quite important. (not this PR though)


if (organization.IsError) return organization.AsError;

return new AutomaticallyConfirmOrganizationUserRequestData
Copy link
Member

Choose a reason for hiding this comment

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

I suggest that it's clearer to call this the ValidationRequest; it's an enriched DTO required by the validator. The overall flow of data then looks like: API request -> Command Request -> Validation Request -> Validation Result -> Command Result -> API response... which is nice and symmetrical. The Data suffix is not very clear by comparison. (it's not a data model)


var successfulConfirmation = await organizationUserRepository.ConfirmOrganizationUserAsync(validatedRequest.OrganizationUser);

if (!successfulConfirmation) return new None();
Copy link
Member

Choose a reason for hiding this comment

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

I think it's also worth explaining here that this is idempotent and designed to handle multiple simultaneous requests from logged in clients.

Copy link
Member

Choose a reason for hiding this comment

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

👏 thank you for moving this. I should've used the v2 convention to begin with.

Comment on lines +54 to +56
var input = await inputTask;
if (input.IsError) return input.AsError;
return await next(input.AsSuccess);
Copy link
Member

Choose a reason for hiding this comment

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

Could this use Match to take advantage of the OneOf library utils? (same for the other util methods)

/// <summary>
/// Enables the Organization Auto Confirm policy for the specified organization.
/// </summary>
public static async Task EnableOrganizationAutoConfirmPolicyAsync<T>(
Copy link
Member

Choose a reason for hiding this comment

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

I think a generic EnablePolicyAsync(PolicyType policyType) method would be helpful, otherwise we're going to end up with a helper method for every policy.

Copy link
Member

Choose a reason for hiding this comment

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

Controller tests are going to get very long; thoughts on making separate files per set of functionality? e.g. autoconfirm endpoints would have their own test file. I did this with unit tests for OrganizationUserControllerPutTests.

}

[Fact]
public async Task AutoConfirm_WhenOwnerInvitesValidUser_ThenShouldReturnNoContent()
Copy link
Member

Choose a reason for hiding this comment

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

Test name: we're testing acceptance, not invitation.

This test should also check the db to verify the user has moved into the correct state (that is, they've actually been confirmed).

@eliykat
Copy link
Member

eliykat commented Nov 1, 2025

Also... enjoy your merge errors 😎

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.

4 participants