Skip to content

Commit 929fb79

Browse files
fix: Redact SSO PII before deletion
1 parent 667de73 commit 929fb79

3 files changed

Lines changed: 29 additions & 15 deletions

File tree

openedx/core/djangoapps/user_api/accounts/tests/test_signals.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ def _create_social_auth(self, uid='user@example.com', extra_data=None):
3333
extra_data=extra_data,
3434
)
3535

36+
def test_get_redacted_social_auth_uid_format(self):
37+
"""
38+
Test that get_redacted_social_auth_uid returns the expected string format.
39+
40+
This is the single source of truth for the redacted uid format.
41+
"""
42+
assert get_redacted_social_auth_uid(42) == 'redacted-before-delete-42@safe.com'
43+
assert get_redacted_social_auth_uid(1) == 'redacted-before-delete-1@safe.com'
44+
3645
def test_signal_warns_and_redacts_when_not_already_redacted(self):
3746
"""
3847
When a UserSocialAuth is deleted without prior redaction, the signal handler

openedx/core/djangoapps/user_api/accounts/tests/test_utils.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
from completion import models
66
from completion.test_utils import CompletionWaffleTestMixin
77
from django.db import connection
8+
from django.db.models.signals import pre_delete
89
from django.test import TestCase
910
from django.test.utils import CaptureQueriesContext, override_settings
1011
from social_django.models import UserSocialAuth
1112

1213
from common.djangoapps.student.models import CourseEnrollment
1314
from common.djangoapps.student.tests.factories import UserFactory
14-
from openedx.core.djangoapps.user_api.accounts.signals import get_redacted_social_auth_uid
15+
from openedx.core.djangoapps.user_api.accounts.signals import get_redacted_social_auth_uid, redact_social_auth_pii_before_deletion
1516
from openedx.core.djangoapps.user_api.accounts.utils import (
1617
redact_and_delete_social_auth,
1718
retrieve_last_sitewide_block_completed,
@@ -145,8 +146,25 @@ def test_retrieve_last_sitewide_block_completed(self):
145146
class RedactAndDeleteSocialAuthTest(TestCase):
146147
"""
147148
Tests for the redact_and_delete_social_auth utility function.
149+
150+
The safety-net pre_delete signal handler is disconnected for all tests in this class
151+
to verify that redact_and_delete_social_auth itself redacts before deleting,
152+
not the fallback signal.
148153
"""
149154

155+
@classmethod
156+
def setUpClass(cls):
157+
super().setUpClass()
158+
# Disconnect the safety-net signal so tests verify redact_and_delete_social_auth
159+
# itself issues the UPDATE before DELETE, not the signal.
160+
pre_delete.disconnect(redact_social_auth_pii_before_deletion, sender=UserSocialAuth)
161+
162+
@classmethod
163+
def tearDownClass(cls):
164+
super().tearDownClass()
165+
# Reconnect the signal after the test class completes.
166+
pre_delete.connect(redact_social_auth_pii_before_deletion, sender=UserSocialAuth)
167+
150168
def setUp(self):
151169
super().setUp()
152170
self.user = UserFactory.create(username='testuser', email='testuser@example.com')
@@ -183,17 +201,6 @@ def create_social_auth(self, provider='google-oauth2', uid='user@example.com', e
183201
extra_data=extra_data,
184202
)
185203

186-
def test_get_redacted_social_auth_uid_format(self):
187-
"""
188-
Test that get_redacted_social_auth_uid returns the expected string format.
189-
190-
This is the single source of truth for the redacted uid format.
191-
If this test breaks, the bulk retirement Concat/Cast in utils.py and
192-
retire_user.py must also be updated to match.
193-
"""
194-
assert get_redacted_social_auth_uid(42) == 'redacted-before-delete-42@safe.com'
195-
assert get_redacted_social_auth_uid(1) == 'redacted-before-delete-1@safe.com'
196-
197204
def test_redact_and_delete_issues_update_before_delete(self):
198205
"""
199206
Test that redact_and_delete_social_auth issues an UPDATE (redaction) before the DELETE.

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,10 @@ def redact_and_delete_social_auth(user_id, skip_delete=False):
211211
212212
``skip_delete`` should only be set to True when called from the pre_delete signal
213213
handler, where deletion is already in progress.
214-
215-
The uid format matches ``get_redacted_social_auth_uid()``.
216214
"""
217215
social_auth_queryset = UserSocialAuth.objects.filter(user_id=user_id)
216+
# Important: this redacted uid must match the format used by ``get_redacted_social_auth_uid()``.
218217
social_auth_queryset.update(
219-
# Important: this redacted uid must match the format used by ``get_redacted_social_auth_uid()``.
220218
uid=Concat(
221219
Value(REDACTED_SOCIAL_AUTH_UID_PREFIX),
222220
Cast('id', output_field=CharField()),

0 commit comments

Comments
 (0)