Skip to content

Commit 83e52e1

Browse files
fix: redacting user retirement data in lms
1 parent 5972c46 commit 83e52e1

File tree

1 file changed

+37
-6
lines changed

1 file changed

+37
-6
lines changed

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

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
from django.contrib.sites.models import Site
1414
from django.core import mail
1515
from django.core.cache import cache
16+
from django.db import connection
1617
from django.test import TestCase
18+
from django.test.utils import CaptureQueriesContext
1719
from django.urls import reverse
1820
from enterprise.models import (
1921
EnterpriseCourseEnrollment,
@@ -1095,17 +1097,32 @@ def test_simple_success(self):
10951097
def test_redaction_before_deletion(self):
10961098
"""
10971099
Verify that redaction (UPDATE) happens before deletion (DELETE).
1098-
Uses assertNumQueries to verify UPDATE queries execute before DELETE queries.
1099-
This protects PII from being exposed in soft-deletes to downstream data warehouses.
1100+
Captures actual SQL queries to ensure UPDATE queries contain redacted values.
11001101
"""
1101-
# Use assertNumQueries to capture and verify the SQL queries execute in correct order.
1102-
with self.assertNumQueries(53): # Full request with 9 UPDATEs (redaction) + 9 DELETEs
1102+
with CaptureQueriesContext(connection) as context:
11031103
self.cleanup_and_assert_status()
11041104

11051105
# Verify records are deleted after redaction
11061106
retirements = UserRetirementStatus.objects.all()
11071107
assert retirements.count() == 0
11081108

1109+
# Verify UPDATE queries exist with default 'redacted' value
1110+
queries = context.captured_queries
1111+
update_queries = [q for q in queries if 'UPDATE' in q['sql'] and 'user_api_userretirementstatus' in q['sql']]
1112+
delete_queries = [q for q in queries if 'DELETE' in q['sql'] and 'user_api_userretirementstatus' in q['sql']]
1113+
1114+
# Should have 9 UPDATE and 9 DELETE queries
1115+
assert len(update_queries) == 9, f"Expected 9 UPDATE queries, found {len(update_queries)}"
1116+
assert len(delete_queries) == 9, f"Expected 9 DELETE queries, found {len(delete_queries)}"
1117+
1118+
# Verify UPDATE queries contain the redacted values
1119+
for update_query in update_queries:
1120+
sql = update_query['sql']
1121+
assert "'redacted'" in sql, f"UPDATE query missing 'redacted' value: {sql}"
1122+
assert 'original_username' in sql, f"UPDATE query missing original_username field: {sql}"
1123+
assert 'original_email' in sql, f"UPDATE query missing original_email field: {sql}"
1124+
assert 'original_name' in sql, f"UPDATE query missing original_name field: {sql}"
1125+
11091126
def test_custom_redacted_values(self):
11101127
"""Test that custom redacted values are applied before deletion."""
11111128
custom_username = 'username-redacted-12345'
@@ -1118,12 +1135,26 @@ def test_custom_redacted_values(self):
11181135
'redacted_email': custom_email,
11191136
'redacted_name': custom_name
11201137
}
1121-
self.cleanup_and_assert_status(data=data)
11221138

1123-
# Records should be deleted after redaction
1139+
with CaptureQueriesContext(connection) as context:
1140+
self.cleanup_and_assert_status(data=data)
1141+
1142+
# Verify records are deleted after redaction
11241143
retirements = UserRetirementStatus.objects.all()
11251144
assert retirements.count() == 0
11261145

1146+
# Verify UPDATE queries contain the custom redacted values
1147+
queries = context.captured_queries
1148+
update_queries = [q for q in queries if 'UPDATE' in q['sql'] and 'user_api_userretirementstatus' in q['sql']]
1149+
1150+
assert len(update_queries) == 9, f"Expected 9 UPDATE queries, found {len(update_queries)}"
1151+
1152+
for update_query in update_queries:
1153+
sql = update_query['sql']
1154+
assert custom_username in sql, f"UPDATE query missing custom username '{custom_username}': {sql}"
1155+
assert custom_email in sql, f"UPDATE query missing custom email '{custom_email}': {sql}"
1156+
assert custom_name in sql, f"UPDATE query missing custom name '{custom_name}': {sql}"
1157+
11271158
def test_leaves_other_users(self):
11281159
remaining_usernames = []
11291160

0 commit comments

Comments
 (0)