Harden archive organization scoping

Validate ArchiveUser organization input against the loaded profile and\nuse the profile organization for owner checks and webhook emission.\n\nAlso disable both PersonPage destructive actions while either archive\nor remove mutation is pending to prevent double-submit races.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
This commit is contained in:
Cursor Agent
2026-05-27 19:13:51 +00:00
committed by Bryan Frimin
parent 7bb3c144a3
commit f50289a755
2 changed files with 9 additions and 4 deletions

View File

@@ -89,6 +89,7 @@ export function PersonPage(props: { queryRef: PreloadedQuery<PersonPageQuery> })
errorMessage: __("Failed to remove person"),
},
);
const isMutating = isArchiving || isRemoving;
const handleArchive = () => {
confirm(
@@ -171,7 +172,7 @@ export function PersonPage(props: { queryRef: PreloadedQuery<PersonPageQuery> })
<DropdownItem
icon={IconArchive}
onClick={handleArchive}
disabled={isArchiving}
disabled={isMutating}
>
{__("Archive")}
</DropdownItem>
@@ -181,7 +182,7 @@ export function PersonPage(props: { queryRef: PreloadedQuery<PersonPageQuery> })
variant="danger"
icon={IconTrashCan}
onClick={handleRemove}
disabled={isRemoving}
disabled={isMutating}
>
{__("Remove")}
</DropdownItem>

View File

@@ -331,6 +331,10 @@ func (s *OrganizationService) RemoveUser(
return NewUserManagedBySCIMError(profileID)
}
if profile.OrganizationID != organizationID {
return NewProfileNotFoundError(profileID)
}
membership := &coredata.Membership{}
if err := membership.LoadByIdentityIDAndOrganizationID(ctx, tx, scope, profile.IdentityID, profile.OrganizationID); err != nil {
return fmt.Errorf("cannot load membership: %w", err)
@@ -339,7 +343,7 @@ func (s *OrganizationService) RemoveUser(
if membership.Role == coredata.MembershipRoleOwner && profile.State == coredata.ProfileStateActive {
profiles := coredata.MembershipProfiles{}
count, err := profiles.CountActiveOwnerByOrganizationID(ctx, tx, scope, organizationID)
count, err := profiles.CountActiveOwnerByOrganizationID(ctx, tx, scope, profile.OrganizationID)
if err != nil {
return fmt.Errorf("cannot count active owners: %w", err)
}
@@ -437,7 +441,7 @@ func (s *OrganizationService) ArchiveUser(
return fmt.Errorf("cannot update membership: %w", err)
}
if err := webhook.InsertData(ctx, tx, scope, organizationID, coredata.WebhookEventTypeUserUpdated, webhooktypes.NewUser(&profile, membership)); err != nil {
if err := webhook.InsertData(ctx, tx, scope, profile.OrganizationID, coredata.WebhookEventTypeUserUpdated, webhooktypes.NewUser(&profile, membership)); err != nil {
return fmt.Errorf("cannot insert webhook event: %w", err)
}