Skip to content

feat: replace user identity strings with user IDs - #38775

Merged
robrap merged 35 commits into
openedx:masterfrom
ttak-apphelix:ttak/BOMS-641
Aug 28, 2026
Merged

feat: replace user identity strings with user IDs#38775
robrap merged 35 commits into
openedx:masterfrom
ttak-apphelix:ttak/BOMS-641

Conversation

@ttak-apphelix

@ttak-apphelix ttak-apphelix commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Update application logging to prevent exposure of customer identity information in logs when SQUELCH_PII_IN_LOGS is enabled. Log records that currently include usernames, email addresses, or other user-identifying strings should instead use non-PII identifiers (for example, numeric user IDs) where appropriate.
This change should be applied consistently across the platform to reduce PII exposure in logs

Private JIRA ticket:
https://2u-internal.atlassian.net/browse/BOMS-641

@ttak-apphelix
ttak-apphelix requested review from a team as code owners June 17, 2026 12:46
Comment thread lms/djangoapps/bulk_user_retirement/views.py Outdated
Comment thread lms/djangoapps/instructor/views/api.py Outdated
Comment thread cms/djangoapps/course_creators/admin.py Outdated

@robrap robrap left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't finish, so I might have missed other things, but I'd rather go through after clean-up of the types of issues I already pointed out. Thank you.

Comment thread cms/djangoapps/course_creators/admin.py Outdated
Comment thread cms/djangoapps/course_creators/admin.py Outdated
Comment thread common/djangoapps/student/models/course_enrollment.py Outdated
Comment thread common/djangoapps/student/models/course_enrollment.py Outdated
Comment thread common/djangoapps/student/models/course_enrollment.py Outdated
Comment thread common/djangoapps/student/views/management.py Outdated
try:
ace.send(msg)
except Exception: # pylint: disable=broad-except
log.warning('Unable to send confirmation email to old address', exc_info=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Why did this need to change? It wasn't including any user arguments?
  • Note: If you remove this, you could probably remove the # pylint: disable=too-many-statements that was added earlier as well.
  1. Are there other cases like this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. My bad, reverted the changes
  2. Removed # pylint: disable=too-many-statements
  3. NO

Comment thread lms/djangoapps/bulk_user_retirement/views.py Outdated
Comment thread lms/djangoapps/course_goals/management/commands/goal_reminder_email.py Outdated
Comment thread lms/djangoapps/courseware/views/views.py Outdated
Comment thread lms/djangoapps/course_goals/management/commands/goal_reminder_email.py Outdated
Comment thread lms/djangoapps/bulk_user_retirement/views.py Outdated
Comment thread lms/djangoapps/instructor/views/api.py Outdated
Comment thread lms/djangoapps/instructor/views/instructor_task_helpers.py Outdated

@robrap robrap left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High-level feedback:

  • I'm not certain how important this work is, so let's fix the most obvious issues, and possible skip things that are more debatable.
  • This is linked to @Akanshu-2u's work on linting. Let's ensure that that linter is only finding major issues, or isn't used at all.
    Thanks.
  • Also, I gave a number of example of patterns. Many of these I had given already, but it isn't what I am seeing. I'm not going to comment on every one, but I want the patterns to be reviewed for each case.

Comment thread common/djangoapps/student/models/course_enrollment.py Outdated

@ktyagiapphelix2u ktyagiapphelix2u left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ttak-apphelix

Copy link
Copy Markdown
Contributor Author

@robrap PR has been internally reviewed. Can you please relook the changes

@ttak-apphelix

Copy link
Copy Markdown
Contributor Author

@robrap Commenting for visibility

@robrap robrap left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience.

Comment thread cms/djangoapps/course_creators/tests/test_admin.py Outdated
Comment thread cms/djangoapps/course_creators/tests/test_admin.py Outdated
Comment thread common/djangoapps/student/models/course_enrollment.py
Comment thread common/djangoapps/student/models/user.py Outdated
Comment thread common/djangoapps/student/models/user.py Outdated
Comment thread lms/djangoapps/bulk_user_retirement/views.py Outdated
Comment thread lms/djangoapps/instructor/views/api.py Outdated
Comment thread lms/djangoapps/instructor/views/api.py Outdated
Comment on lines +77 to +80
failed_emails_for_log = (
'[REDACTED]' if getattr(settings, 'SQUELCH_PII_IN_LOGS', False) else pformat(failed_emails)
)
log.error('Failed emails:%s', failed_emails_for_log)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Minor improvement that is independent.
Suggested change
failed_emails_for_log = (
'[REDACTED]' if getattr(settings, 'SQUELCH_PII_IN_LOGS', False) else pformat(failed_emails)
)
log.error('Failed emails:%s', failed_emails_for_log)
failed_emails_for_log = (
'[REDACTED]' if getattr(settings, 'SQUELCH_PII_IN_LOGS', False) else pformat(failed_emails)
)
log.error('Failed emails for manual verification: %s', failed_emails_for_log)
  1. I don't love that this makes the error message almost useless, because we don't know which ones failed or passed, and thus how to recover. Can we ticket a follow-up, or do a follow-up PR to improve _generate_manual_verification_from_file to return failed indices as well? This doesn't need to block this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Updated
  2. Will create a follow up ticket for this

Comment thread lms/djangoapps/verify_student/management/commands/manual_verifications.py Outdated
@ttak-apphelix

Copy link
Copy Markdown
Contributor Author

@robrap FYI
uv run ruff check --output-format=github

this fails for all [.format(...)] calls if we don't use f-strings.

@robrap robrap left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor comments. Thanks. Let's review/merge on Friday.

and call.args[0] == "Unable to send course creator status e-mail to %s"
and str(self.user.id) in str(call.args[1])
for call in mock_log.warning.call_args_list
def assert_case(squelch_pii, states):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: assert_case => test_and_assert_case

I like when assert_ functions just help with asserting on test output values, but this method is actually performing the feature under test as well, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated
I like when assert_ functions just help with asserting on test output values, but this method is actually performing the feature under test as well, right? - That's correct

Comment thread lms/djangoapps/instructor/views/api.py Outdated
Comment on lines +465 to +470
email_for_log, user_identifier_for_log = (
('[REDACTED]', f' for user {user.id}')
if getattr(settings, 'SQUELCH_PII_IN_LOGS', False)
else (email, '')
)
log.warning('email %s already exists%s', email_for_log, user_identifier_for_log)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we had to have two different messages, your original code with two log.warning calls would be nicer.
The following is much simpler to read and follow, even though it is a slightly awkward message in the case of squelching. Please choose this or your original. I like this, but you may disagree.

                          user_identifier_for_log = (
                                user.id)
                                if getattr(settings, 'SQUELCH_PII_IN_LOGS', False)
                                else email
                            )
                            log.warning('email for user (%s) already exists', user_identifier_for_log)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

@robrap
robrap enabled auto-merge (squash) August 28, 2026 12:21
@robrap
robrap disabled auto-merge August 28, 2026 12:21
@robrap
robrap enabled auto-merge (squash) August 28, 2026 12:22
@robrap
robrap merged commit 52c9990 into openedx:master Aug 28, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants