Skip to content

Commit

Permalink
chore: Add missing PII annotations, update safelist
Browse files Browse the repository at this point in the history
PII Annotations are very out of date, this commit adds most that were
missing in edx-platform, and some additional annotations to the
safelist. It is not comprehensive, several other upstream Open edX
packages also need to be updated. It also does not include removing
annotations that have been moved upstream, or been removed entirely.
Those are separate follow-on tasks.
  • Loading branch information
bmtcril committed Nov 5, 2024
1 parent 3a535d8 commit e478975
Show file tree
Hide file tree
Showing 21 changed files with 188 additions and 10 deletions.
96 changes: 91 additions & 5 deletions .annotation_safe_list.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@

# Via Django
auth.Group:
".. no_pii:" : "No PII"
".. no_pii:": "No PII"
auth.Permission:
".. no_pii:" : "No PII"
".. no_pii:": "No PII"
auth.User:
".. pii:": "Contains username, password, and email address, retired in AccountRetirementView"
".. pii_types:" : username, email_address, password
".. pii_retirement:" : local_api
".. pii_types:": username, email_address, password
".. pii_retirement:": local_api
contenttypes.ContentType:
".. no_pii:": "No PII"
admin.LogEntry:
Expand All @@ -27,6 +27,66 @@ sessions.Session:
sites.Site:
".. no_pii:": "No PII"

# Automatically generated edx-platform models that can't be annotated
calendar_sync.HistoricalUserCalendarSyncConfig:
".. no_pii:": "No PII"
certificates.HistoricalCertificateAllowlist:
".. no_pii:": "No PII"
certificates.HistoricalCertificateDateOverride:
".. no_pii:": "No PII"
certificates.HistoricalCertificateInvalidation:
".. no_pii:": "No PII"
certificates.HistoricalGeneratedCertificate:
".. pii:": "PII can exist in the generated certificate linked to in this model. Certificate data is currently retained."
".. pii_types:": "name, username"
".. pii_retirement:": "retained"
course_apps.HistoricalCourseAppStatus:
".. no_pii:": "No PII"
course_goals.HistoricalCourseGoal:
".. no_pii:": "No PII"
course_live.HistoricalCourseLiveConfiguration:
".. no_pii:": "No PII"
course_modes.HistoricalCourseMode:
".. no_pii:": "No PII"
course_overviews.HistoricalCourseOverview:
".. no_pii:": "No PII"
discussions.HistoricalDiscussionsConfiguration:
".. no_pii:": "No PII"
entitlements.HistoricalCourseEntitlement:
".. no_pii:": "No PII"
entitlements.HistoricalCourseEntitlementSupportDetail:
".. no_pii:": "No PII"
experiments.HistoricalExperimentKeyValue:
".. no_pii:": "No PII"
external_user_ids.HistoricalExternalId:
".. no_pii:": "We store external_user_id here, but do not consider that PII under OEP-30."
external_user_ids.HistoricalExternalIdType:
".. no_pii:": "No PII"
grades.HistoricalPersistentSubsectionGradeOverride:
".. no_pii:": "No PII"
instructor_task.HistoricalInstructorTaskSchedule:
".. no_pii:": "No PII"
program_enrollments.HistoricalProgramCourseEnrollment:
".. no_pii:": "No PII"
program_enrollments.HistoricalProgramEnrollment:
".. pii:": "PII is found in the external key for a program enrollment"
".. pii_types:": "other"
".. pii_retirement:": "local_api"
programs.HistoricalProgramDiscussionsConfiguration:
".. no_pii:": "No PII"
programs.HistoricalProgramLiveConfiguration:
".. no_pii:": "No PII"
schedules.HistoricalSchedule:
".. no_pii:": "No PII"
split_modulestore_django.HistoricalSplitModulestoreCourseIndex:
".. no_pii:": "No PII"
student.HistoricalCourseEnrollment:
".. no_pii:": "No PII"
student.HistoricalManualEnrollmentAudit:
".. pii:": "Contains enrolled_email, retired in LMSAccountRetirementView"
".. pii_types:": "email_address"
".. pii_retirement:": "local_api"

# Automatically generated models in edx-enterprise that can't be annotated there
consent.HistoricalDataSharingConsent:
".. pii:": "The username field inherited from Consent contains PII."
Expand All @@ -45,7 +105,7 @@ enterprise.HistoricalEnterpriseCustomerCatalog:
enterprise.HistoricalEnterpriseCustomerEntitlement:
".. no_pii:": "No PII"

# Via ORA2
# Via edx-ora2, these can be removed once the models are annotated for real
assessment.Assessment:
".. no_pii:": "No PII"
assessment.AssessmentFeedback:
Expand Down Expand Up @@ -127,10 +187,24 @@ djcelery.TaskState:
djcelery.WorkerState:
".. no_pii:": "No PII"

# Via django-celery-results
django_celery_results.ChordCounter:
".. no_pii:": "No PII"
django_celery_results.GroupResult:
".. no_pii:": "No PII"
django_celery_results.TaskResult:
".. no_pii:": "No PII"

# Via edx-oauth2-provider https://github.com/edx/edx-oauth2-provider
edx_oauth2_provider.TrustedClient:
".. no_pii:": "No PII"

# Via edx-name-affirmation, not part of the openedx org
edx_name_affirmation.HistoricalVerifiedName:
".. pii:": "Contains name fields."
".. pii_types:": "name"
".. pii_retirement:": "local_api"

# Via VAL
edxval.CourseVideo:
".. no_pii:": "No PII"
Expand All @@ -149,6 +223,12 @@ edxval.VideoImage:
edxval.VideoTranscript:
".. no_pii:": "No PII"

# Via PyLTI1p3
lti1p3_tool_config.LtiTool:
".. no_pii:": "No PII"
lti1p3_tool_config.LtiToolKey:
".. no_pii:": "No PII"

# Via Milestones
milestones.CourseContentMilestone:
".. no_pii:": "No PII"
Expand Down Expand Up @@ -190,6 +270,10 @@ oauth2_provider.Grant:
".. pii:": "Contains 3rd party authentication secrets. Retired in DeactivateLogoutView."
".. pii_types:": password, other
".. pii_retirement:": local_api
oauth2_provider.IDToken:
".. pii:": "Contains 3rd party authentication secrets, currently this is retained until the token times out, but should be retired explicitly with the other models from this package."
".. pii_types:": password, other
".. pii_retirement:": retained
oauth2_provider.RefreshToken:
".. pii:": "Contains 3rd party authentication secrets. Retired in DeactivateLogoutView."
".. pii_types:": password, other
Expand Down Expand Up @@ -250,6 +334,8 @@ submissions.StudentItem:
".. no_pii:": "No PII"
submissions.Submission:
".. no_pii:": "No PII"
submissions.TeamSubmission:
".. no_pii:": "No PII"

# Via sorl-thumbnail https://github.com/jazzband/sorl-thumbnail
thumbnail.KVStore:
Expand Down
4 changes: 3 additions & 1 deletion common/djangoapps/student/models/course_enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -1750,7 +1750,7 @@ def refund_window(self, refund_window):

class BulkUnenrollConfiguration(ConfigurationModel): # lint-amnesty, pylint: disable=empty-docstring
"""
.. no_pii:
"""
csv_file = models.FileField(
validators=[FileExtensionValidator(allowed_extensions=['csv'])],
Expand All @@ -1763,6 +1763,8 @@ class BulkUnenrollConfiguration(ConfigurationModel): # lint-amnesty, pylint: di
class BulkChangeEnrollmentConfiguration(ConfigurationModel):
"""
config model for the bulk_change_enrollment_csv command
.. no_pii:
"""
csv_file = models.FileField(
validators=[FileExtensionValidator(allowed_extensions=['csv'])],
Expand Down
4 changes: 4 additions & 0 deletions common/djangoapps/student/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,8 @@ class AllowedAuthUser(TimeStampedModel):
class AccountRecoveryConfiguration(ConfigurationModel):
"""
configuration model for recover account management command
.. no_pii:
"""
csv_file = models.FileField(
validators=[FileExtensionValidator(allowed_extensions=['csv'])],
Expand Down Expand Up @@ -1824,6 +1826,8 @@ def perform_streak_updates(cls, user, course_key, browser_timezone=None):
class UserPasswordToggleHistory(TimeStampedModel):
"""
Keeps track of user password disable/enable history
.. no_pii:
"""
user = models.ForeignKey(User, related_name='password_toggle_history', on_delete=models.CASCADE)
comment = models.CharField(max_length=255, help_text=_("Add a reason"), blank=True, null=True)
Expand Down
2 changes: 2 additions & 0 deletions lms/djangoapps/course_goals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class CourseGoalReminderStatus(TimeStampedModel):
Tracks whether we've sent a reminder about a particular goal this week.
See the management command goal_reminder_email for more detail about how this is used.
.. no_pii:
"""
class Meta:
verbose_name_plural = "Course goal reminder statuses"
Expand Down
2 changes: 2 additions & 0 deletions lms/djangoapps/course_home_api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
class DisableProgressPageStackedConfig(StackedConfigurationModel):
"""
Stacked Config Model for disabling the frontend-app-learning progress page
.. no_pii:
"""

STACKABLE_FIELDS = ('disabled',)
Expand Down
2 changes: 2 additions & 0 deletions lms/djangoapps/courseware/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,8 @@ class Meta:
class FinancialAssistanceConfiguration(ConfigurationModel):
"""
Manages configuration for connecting to Financial Assistance backend service and using its API.
.. no_pii:
"""

api_base_url = models.URLField(
Expand Down
1 change: 1 addition & 0 deletions lms/djangoapps/experiments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class ExperimentKeyValue(TimeStampedModel):
"""
ExperimentData stores any generic key-value associated with experiments
identified by experiment_id.
.. no_pii:
"""
experiment_id = models.PositiveSmallIntegerField(
Expand Down
4 changes: 4 additions & 0 deletions lms/djangoapps/support/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
class CourseResetCourseOptIn(TimeStampedModel):
"""
Model that represents a course which has opted in to the course reset feature.
.. no_pii:
"""
course_id = CourseKeyField(max_length=255, unique=True)
active = BooleanField()
Expand All @@ -40,6 +42,8 @@ def all_active_course_ids():
class CourseResetAudit(TimeStampedModel):
"""
Model which records the course reset action's status and metadata
.. no_pii:
"""
class CourseResetStatus(TextChoices):
IN_PROGRESS = "in_progress"
Expand Down
2 changes: 2 additions & 0 deletions lms/djangoapps/user_tours/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class CourseHomeChoices(models.TextChoices):
class UserDiscussionsTours(models.Model):
"""
Model to track which discussions tours a user has seen.
.. no_pii:
"""
tour_name = models.CharField(max_length=255)
show_tour = models.BooleanField(default=True)
Expand Down
10 changes: 8 additions & 2 deletions lms/djangoapps/verify_student/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1177,8 +1177,10 @@ def deadline_for_course(cls, course_key):

class SSPVerificationRetryConfig(ConfigurationModel): # pylint: disable=model-missing-unicode, useless-suppression
"""
SSPVerificationRetryConfig used to inject arguments
to retry_failed_photo_verifications management command
SSPVerificationRetryConfig used to inject arguments
to retry_failed_photo_verifications management command
.. no_pii:
"""

class Meta:
Expand All @@ -1201,6 +1203,10 @@ class VerificationAttempt(StatusModel):
Plugins that implement forms of IDV can store information about IDV attempts in this model for use across
the platform.
.. pii: Contains the name of the user
.. pii_types: name
.. pii_retirement: local_api
"""
user = models.ForeignKey(User, db_index=True, on_delete=models.CASCADE)
name = models.CharField(blank=True, max_length=255)
Expand Down
6 changes: 6 additions & 0 deletions openedx/core/djangoapps/agreements/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class Meta:
class LTIPIITool(TimeStampedModel):
"""
This model stores the relationship between a course and the LTI tools in the course that share PII.
.. no_pii:
"""
course_key = CourseKeyField(max_length=255, unique=True, db_index=True)
lti_tools = models.JSONField()
Expand All @@ -39,6 +41,8 @@ class Meta:
class LTIPIISignature(TimeStampedModel):
"""
This model stores a user's acknowledgement to share PII via LTI tools in a particular course.
.. no_pii:
"""
user = models.ForeignKey(User, db_index=True, on_delete=models.CASCADE)
course_key = CourseKeyField(max_length=255, db_index=True)
Expand All @@ -57,6 +61,8 @@ class Meta:
class ProctoringPIISignature(TimeStampedModel):
"""
This model stores a user's acknowledgment to share PII via proctoring in a particular course.
.. no_pii:
"""
user = models.ForeignKey(User, db_index=True, on_delete=models.CASCADE)
course_key = CourseKeyField(max_length=255, db_index=True)
Expand Down
Loading

0 comments on commit e478975

Please sign in to comment.