diff --git a/common/djangoapps/third_party_auth/models.py b/common/djangoapps/third_party_auth/models.py index 2a71b2d17d7f..0460d10fec1c 100644 --- a/common/djangoapps/third_party_auth/models.py +++ b/common/djangoapps/third_party_auth/models.py @@ -681,17 +681,21 @@ class SAMLProviderConfig(ProviderConfig): default_last_name = models.CharField( max_length=255, blank=True, verbose_name="Default Value for Last Name", help_text="Default value for last name to be used if not present in SAML response.") + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 attr_username = models.CharField( max_length=128, blank=True, verbose_name="Username Hint Attribute", help_text="URN of SAML attribute to use as a suggested username for this user. Leave blank for default." ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 default_username = models.CharField( max_length=255, blank=True, verbose_name="Default Value for Username", help_text="Default value for username to be used if not present in SAML response." ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 attr_email = models.CharField( max_length=128, blank=True, verbose_name="Email Attribute", help_text="URN of SAML attribute containing the user's email address[es]. Leave blank for default.") + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 default_email = models.CharField( max_length=255, blank=True, verbose_name="Default Value for Email", help_text="Default value for email to be used if not present in SAML response." @@ -739,6 +743,7 @@ class SAMLProviderConfig(ProviderConfig): "for trusted providers that are known to provide accurate user information." ), ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 skip_email_verification = models.BooleanField( default=True, help_text=_( @@ -761,6 +766,7 @@ class SAMLProviderConfig(ProviderConfig): "are skipped, their values are inferred as False (opted out)." ), ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 disable_email_editing = models.BooleanField( default=False, help_text=_( diff --git a/lms/djangoapps/bulk_email/models.py b/lms/djangoapps/bulk_email/models.py index b1a7aa574408..961d268dc85b 100644 --- a/lms/djangoapps/bulk_email/models.py +++ b/lms/djangoapps/bulk_email/models.py @@ -433,6 +433,7 @@ class Meta: course_id = CourseKeyField(max_length=255, db_index=True, unique=True) # Whether or not to enable instructor email + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 email_enabled = models.BooleanField(default=False) @classmethod @@ -495,6 +496,7 @@ class BulkEmailFlag(ConfigurationModel): .. toggle_creation_date: 2016-05-05 """ # boolean field 'enabled' inherited from parent ConfigurationModel + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 require_course_email_auth = models.BooleanField(default=True) @classmethod diff --git a/lms/djangoapps/course_goals/models.py b/lms/djangoapps/course_goals/models.py index 616966600040..8d53b508507c 100644 --- a/lms/djangoapps/course_goals/models.py +++ b/lms/djangoapps/course_goals/models.py @@ -86,6 +86,7 @@ class Meta: verbose_name_plural = "Course goal reminder statuses" goal = models.OneToOneField(CourseGoal, on_delete=models.CASCADE, related_name='reminder_status') + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 email_reminder_sent = models.BooleanField( default=False, help_text='Tracks if the email reminder to complete the Course Goal has been sent this week.' ) diff --git a/lms/djangoapps/courseware/models.py b/lms/djangoapps/courseware/models.py index 500629945141..24b88bbec697 100644 --- a/lms/djangoapps/courseware/models.py +++ b/lms/djangoapps/courseware/models.py @@ -564,6 +564,7 @@ class FinancialAssistanceConfiguration(ConfigurationModel): help_text=_('Financial Assistance Backend API Base URL.') ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 service_username = models.CharField( max_length=100, default='financial_assistance_service_user', diff --git a/openedx/core/djangoapps/catalog/models.py b/openedx/core/djangoapps/catalog/models.py index 98a012e3c365..77dabcc9325c 100644 --- a/openedx/core/djangoapps/catalog/models.py +++ b/openedx/core/djangoapps/catalog/models.py @@ -44,6 +44,7 @@ class CatalogIntegration(ConfigurationModel): ) ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 service_username = models.CharField( max_length=100, default='lms_catalog_service_user', diff --git a/openedx/core/djangoapps/content/course_overviews/models.py b/openedx/core/djangoapps/content/course_overviews/models.py index 6389350d6005..a53c9e9b1d14 100644 --- a/openedx/core/djangoapps/content/course_overviews/models.py +++ b/openedx/core/djangoapps/content/course_overviews/models.py @@ -57,7 +57,9 @@ class CourseOverview(TimeStampedModel): will cause a slew of modulestore reads as each course needs to be re-cached into the course overview. - .. no_pii: + .. pii: Contains proctoring_escalation_email, a staff contact address copied from CourseFields. + .. pii_types: email_address + .. pii_retirement: retained """ class Meta: diff --git a/openedx/core/djangoapps/credit/models.py b/openedx/core/djangoapps/credit/models.py index 9c14a15104b9..a70fbd1cd292 100644 --- a/openedx/core/djangoapps/credit/models.py +++ b/openedx/core/djangoapps/credit/models.py @@ -115,6 +115,7 @@ class CreditProvider(TimeStampedModel): ) ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 eligibility_email_message = models.TextField( default="", help_text=gettext_lazy( @@ -124,6 +125,7 @@ class CreditProvider(TimeStampedModel): ) ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 receipt_email_message = models.TextField( default="", help_text=gettext_lazy( @@ -424,7 +426,9 @@ class CreditRequirementStatus(TimeStampedModel): In case (3), no CreditRequirementStatus record will exist for the requirement and user. - .. no_pii: + .. pii: Contains username, anonymized by retire_user(). + .. pii_types: username + .. pii_retirement: local_api """ REQUIREMENT_STATUS_CHOICES = ( @@ -545,7 +549,9 @@ class CreditEligibility(TimeStampedModel): """ A record of a user's eligibility for credit for a specific course. - .. no_pii: + .. pii: Contains username, anonymized by retire_user(). + .. pii_types: username + .. pii_retirement: local_api """ username = models.CharField(max_length=255, db_index=True) course = models.ForeignKey(CreditCourse, related_name="eligibilities", on_delete=models.CASCADE) @@ -658,7 +664,9 @@ class CreditRequest(TimeStampedModel): (perhaps because the user did not finish filling in forms on the credit provider's site), the request record will be updated, but the UUID will remain the same. - .. no_pii: + .. pii: Contains username, anonymized by retire_user(). + .. pii_types: username + .. pii_retirement: local_api """ uuid = models.CharField(max_length=32, unique=True, db_index=True) diff --git a/openedx/core/djangoapps/django_comment_common/models.py b/openedx/core/djangoapps/django_comment_common/models.py index bd7b8fe66e67..42f24cf8a169 100644 --- a/openedx/core/djangoapps/django_comment_common/models.py +++ b/openedx/core/djangoapps/django_comment_common/models.py @@ -239,6 +239,7 @@ class CourseDiscussionSettings(models.Model): help_text="Key/value store mapping discussion IDs to discussion XBlock usage keys.", ) always_divide_inline_discussions = models.BooleanField(default=False) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 reported_content_email_notifications = models.BooleanField(default=False) _divided_discussions = models.TextField(db_column='divided_discussions', null=True, blank=True) # JSON list diff --git a/openedx/core/djangoapps/notifications/models.py b/openedx/core/djangoapps/notifications/models.py index b3a93e74e329..ab055148c725 100644 --- a/openedx/core/djangoapps/notifications/models.py +++ b/openedx/core/djangoapps/notifications/models.py @@ -146,6 +146,7 @@ class Notification(TimeStampedModel): content_context = models.JSONField(default=dict) content_url = models.URLField(null=True, blank=True) web = models.BooleanField(default=True, null=False, blank=False) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 email = models.BooleanField(default=False, null=False, blank=False) push = models.BooleanField(default=False, null=False, blank=False) last_read = models.DateTimeField(null=True, blank=True) @@ -184,7 +185,9 @@ class Meta: app = models.CharField(max_length=128, null=False, blank=False, db_index=True) web = models.BooleanField(default=True, null=False, blank=False) push = models.BooleanField(default=False, null=False, blank=False) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 email = models.BooleanField(default=False, null=False, blank=False) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 email_cadence = models.CharField(max_length=64, choices=EmailCadenceChoices.choices, null=False, blank=False) is_active = models.BooleanField(default=True) diff --git a/openedx/core/djangoapps/video_pipeline/models.py b/openedx/core/djangoapps/video_pipeline/models.py index 1e21c19feef3..ace83a911b76 100644 --- a/openedx/core/djangoapps/video_pipeline/models.py +++ b/openedx/core/djangoapps/video_pipeline/models.py @@ -38,6 +38,7 @@ class VEMPipelineIntegration(ConfigurationModel): help_text=_('video encode manager API URL.') ) + # pylint: disable-next=pii-invalid-no-pii-annotation # field does not store user PII data, safe under OEP-30 service_username = models.CharField( max_length=100, default='vem_service_user', diff --git a/pylintrc b/pylintrc index 43f2b3bc9eb8..e1b1e841e147 100644 --- a/pylintrc +++ b/pylintrc @@ -64,7 +64,7 @@ # SERIOUSLY. # # ------------------------------ -# Generated by edx-lint version: 5.6.0 +# Generated by edx-lint version: 6.2.0 # ------------------------------ [MASTER] ignore = ,.git,.tox,migrations,node_modules,.pycharm_helpers @@ -257,6 +257,8 @@ enable = deprecated-pragma, unrecognized-inline-option, useless-suppression, + + pii-invalid-no-pii-annotation, disable = bad-indentation, broad-exception-raised, @@ -414,4 +416,9 @@ int-import-graph = [EXCEPTIONS] overgeneral-exceptions = builtins.Exception -# d6e4348dec0a8eb2752fc4fe02315286c298aeff +[PII] +pii-terms = + email, + username + +# e72ecbe0cf2f12ac71fdd2c33dc7bfb778f81c6e diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 488267a56361..6a3fc838d855 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -766,7 +766,7 @@ edx-i18n-tools==1.9.0 # -r requirements/edx/testing.txt # ora2 # xblocks-contrib -edx-lint==5.6.0 +edx-lint==6.2.0 # via -r requirements/edx/testing.txt edx-milestones==1.1.0 # via @@ -2083,6 +2083,7 @@ tomlkit==0.13.3 # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt + # edx-lint # openedx-learning # pylint # snowflake-connector-python diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 7aac5983ae7a..887bed1569ca 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -591,7 +591,7 @@ edx-i18n-tools==1.9.0 # -r requirements/edx/base.txt # ora2 # xblocks-contrib -edx-lint==5.6.0 +edx-lint==6.2.0 # via -r requirements/edx/testing.in edx-milestones==1.1.0 # via -r requirements/edx/base.txt @@ -1546,6 +1546,7 @@ tinycss2==1.4.0 tomlkit==0.13.3 # via # -r requirements/edx/base.txt + # edx-lint # openedx-learning # pylint # snowflake-connector-python