Archive SCIM users with in-use profiles instead of 500ing

When a SCIM hard delete targets a profile that is still referenced
(e.g. completed document version signatures, FK RESTRICT), profile.Delete
fails with 23503 and poisons the surrounding transaction. The existing
deactivate fallback then ran on the aborted transaction and failed with
25P02, surfacing to the connector as an opaque 500 and eventually
disabling the bridge.

Wrap profile.Delete in a savepoint so the FK violation only rolls back
the delete attempt, leaving the outer transaction healthy for the
deactivate/archive fallback. Also map FK violations in Membership.Delete
to ErrResourceInUse for consistency with MembershipProfile.Delete.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
This commit is contained in:
Sacha Al Himdani
2026-07-15 14:30:34 +02:00
parent 944bcb7380
commit f604c48686
4 changed files with 69 additions and 3 deletions

View File

@@ -892,8 +892,18 @@ func (s *Service) DeleteUser(
membership = m
}
if err := profile.Delete(ctx, tx, scope, profile.ID); err != nil {
if errors.Is(err, coredata.ErrResourceInUse) {
deleteErr := tx.Savepoint(
ctx,
func(ctx context.Context, sp pg.Tx) error {
if err := profile.Delete(ctx, sp, scope, profile.ID); err != nil {
return fmt.Errorf("cannot delete profile: %w", err)
}
return nil
},
)
if deleteErr != nil {
if errors.Is(deleteErr, coredata.ErrResourceInUse) {
s.logger.WarnCtx(
ctx,
"SCIM user delete skipped, profile is in use",
@@ -907,7 +917,7 @@ func (s *Service) DeleteUser(
return nil
}
return fmt.Errorf("cannot delete profile: %w", err)
return fmt.Errorf("cannot delete profile in savepoint: %w", deleteErr)
}
invitations := &coredata.Invitations{}