Skip to content

Commit d05cd5a

Browse files
fix: retirement PII leaks by redacting pending secondary email/name data
1 parent f9aa35a commit d05cd5a

3 files changed

Lines changed: 17 additions & 15 deletions

File tree

common/djangoapps/student/tests/test_models.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -740,16 +740,17 @@ def test_retire_recovery_email(self):
740740
AccountRecoveryFactory(user=user, secondary_email='recovery@example.com')
741741
assert len(AccountRecovery.objects.filter(user_id=user.id)) == 1
742742

743+
from django.db.models.signals import pre_delete
743744
saved_emails = []
744745

745-
original_save = AccountRecovery.save
746-
747-
def capture_save(instance, *args, **kwargs):
746+
def capture_pre_delete(sender, instance, **kwargs):
748747
saved_emails.append(instance.secondary_email)
749-
original_save(instance, *args, **kwargs)
750748

751-
with mock.patch.object(AccountRecovery, 'save', side_effect=capture_save):
749+
pre_delete.connect(capture_pre_delete, sender=AccountRecovery)
750+
try:
752751
AccountRecovery.retire_recovery_email(user_id=user.id)
752+
finally:
753+
pre_delete.disconnect(capture_pre_delete, sender=AccountRecovery)
753754

754755
# Record must be gone
755756
assert len(AccountRecovery.objects.filter(user_id=user.id)) == 0
@@ -772,16 +773,17 @@ def test_redact_and_delete_pending_secondary_email(self):
772773
)
773774
assert len(PendingSecondaryEmailChange.objects.filter(user_id=user.id)) == 1
774775

776+
from django.db.models.signals import pre_delete
775777
saved_emails = []
776778

777-
original_save = PendingSecondaryEmailChange.save
778-
779-
def capture_save(instance, *args, **kwargs):
779+
def capture_pre_delete(sender, instance, **kwargs):
780780
saved_emails.append(instance.new_secondary_email)
781-
original_save(instance, *args, **kwargs)
782781

783-
with mock.patch.object(PendingSecondaryEmailChange, 'save', side_effect=capture_save):
782+
pre_delete.connect(capture_pre_delete, sender=PendingSecondaryEmailChange)
783+
try:
784784
PendingSecondaryEmailChange.redact_and_delete_pending_secondary_email(user_id=user.id)
785+
finally:
786+
pre_delete.disconnect(capture_pre_delete, sender=PendingSecondaryEmailChange)
785787

786788
# Record must be gone
787789
assert len(PendingSecondaryEmailChange.objects.filter(user_id=user.id)) == 0

openedx/core/djangoapps/user_api/accounts/views.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1154,7 +1154,6 @@ def post(self, request):
11541154
self.retire_entitlement_support_detail(user)
11551155

11561156
# Retire misc. models that may contain PII of this user
1157-
PendingEmailChange.redact_pending_email_by_user_value(user, field="user")
11581157
PendingEmailChange.delete_by_user_value(user, field="user")
11591158
UserOrgTag.delete_by_user_value(user, field="user")
11601159
PendingSecondaryEmailChange.redact_and_delete_pending_secondary_email(user.id)

openedx/core/djangoapps/user_api/management/tests/test_retire_user.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,15 @@ def test_retire_user_cleans_pending_secondary_email(setup_retirement_states): #
122122
assert PendingSecondaryEmailChange.objects.filter(user=user).exists()
123123

124124
saved_emails = []
125-
original_save = PendingSecondaryEmailChange.save
126125

127-
def capture_save(instance, *args, **kwargs):
126+
def capture_pre_delete(sender, instance, **kwargs):
128127
saved_emails.append(instance.new_secondary_email)
129-
original_save(instance, *args, **kwargs)
130128

131-
with mock.patch.object(PendingSecondaryEmailChange, 'save', side_effect=capture_save):
129+
pre_delete.connect(capture_pre_delete, sender=PendingSecondaryEmailChange)
130+
try:
132131
call_command('retire_user', username=user.username, user_email=user.email)
132+
finally:
133+
pre_delete.disconnect(capture_pre_delete, sender=PendingSecondaryEmailChange)
133134

134135
# Record must be deleted
135136
assert not PendingSecondaryEmailChange.objects.filter(user=user).exists()

0 commit comments

Comments
 (0)