diff --git a/license_manager/apps/api/serializers.py b/license_manager/apps/api/serializers.py index 38a56e78..db612f48 100644 --- a/license_manager/apps/api/serializers.py +++ b/license_manager/apps/api/serializers.py @@ -355,9 +355,10 @@ class Meta: 'subscription_for_auto_applied_licenses', 'available_subscription_catalogs', 'has_custom_license_expiration_messaging', + 'modal_header_text', 'expired_subscription_modal_messaging', - 'hyper_link_text_for_expired_modal', - 'url_for_expired_modal', + 'button_label_in_modal', + 'url_for_button_in_modal', 'enable_auto_applied_subscriptions_with_universal_link' ] diff --git a/license_manager/apps/subscriptions/admin.py b/license_manager/apps/subscriptions/admin.py index 0697816a..9215b09e 100644 --- a/license_manager/apps/subscriptions/admin.py +++ b/license_manager/apps/subscriptions/admin.py @@ -418,9 +418,10 @@ class CustomerAgreementAdmin(admin.ModelAdmin): 'license_duration_before_purge', 'disable_onboarding_notifications', 'has_custom_license_expiration_messaging', + 'modal_header_text', 'expired_subscription_modal_messaging', - 'hyper_link_text_for_expired_modal', - 'url_for_expired_modal', + 'button_label_in_modal', + 'url_for_button_in_modal', 'enable_auto_applied_subscriptions_with_universal_link' ) custom_fields = ('subscription_for_auto_applied_licenses',) diff --git a/license_manager/apps/subscriptions/migrations/0072_remove_customeragreement_hyper_link_text_for_expired_modal_and_more.py b/license_manager/apps/subscriptions/migrations/0072_remove_customeragreement_hyper_link_text_for_expired_modal_and_more.py new file mode 100644 index 00000000..dea4eeca --- /dev/null +++ b/license_manager/apps/subscriptions/migrations/0072_remove_customeragreement_hyper_link_text_for_expired_modal_and_more.py @@ -0,0 +1,69 @@ +# Generated by Django 4.2.16 on 2024-10-14 10:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('subscriptions', '0071_customeragreement_enable_auto_applied_subscriptions_with_universal_link_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='customeragreement', + name='hyper_link_text_for_expired_modal', + ), + migrations.RemoveField( + model_name='customeragreement', + name='url_for_expired_modal', + ), + migrations.RemoveField( + model_name='historicalcustomeragreement', + name='hyper_link_text_for_expired_modal', + ), + migrations.RemoveField( + model_name='historicalcustomeragreement', + name='url_for_expired_modal', + ), + migrations.AddField( + model_name='customeragreement', + name='button_label_in_modal', + field=models.CharField(blank=True, help_text='The text that will appear as on the button in the expiration modal', max_length=255, null=True), + ), + migrations.AddField( + model_name='customeragreement', + name='modal_header_text', + field=models.CharField(blank=True, help_text='The bold text that will appear as the header in the expiration modal.', max_length=512, null=True), + ), + migrations.AddField( + model_name='customeragreement', + name='url_for_button_in_modal', + field=models.CharField(blank=True, help_text='The URL that should underly the sole button in the expiration modal', max_length=512, null=True), + ), + migrations.AddField( + model_name='historicalcustomeragreement', + name='button_label_in_modal', + field=models.CharField(blank=True, help_text='The text that will appear as on the button in the expiration modal', max_length=255, null=True), + ), + migrations.AddField( + model_name='historicalcustomeragreement', + name='modal_header_text', + field=models.CharField(blank=True, help_text='The bold text that will appear as the header in the expiration modal.', max_length=512, null=True), + ), + migrations.AddField( + model_name='historicalcustomeragreement', + name='url_for_button_in_modal', + field=models.CharField(blank=True, help_text='The URL that should underly the sole button in the expiration modal', max_length=512, null=True), + ), + migrations.AlterField( + model_name='customeragreement', + name='expired_subscription_modal_messaging', + field=models.TextField(blank=True, help_text='The content of a modal that will appear to learners upon subscription expiration. This text can be used for custom guidance per customer.', null=True), + ), + migrations.AlterField( + model_name='historicalcustomeragreement', + name='expired_subscription_modal_messaging', + field=models.TextField(blank=True, help_text='The content of a modal that will appear to learners upon subscription expiration. This text can be used for custom guidance per customer.', null=True), + ), + ] diff --git a/license_manager/apps/subscriptions/models.py b/license_manager/apps/subscriptions/models.py index edffda87..864500a3 100644 --- a/license_manager/apps/subscriptions/models.py +++ b/license_manager/apps/subscriptions/models.py @@ -56,6 +56,7 @@ provision_licenses, ) +from license_manager.apps.subscriptions.sanitize import sanitize_html from .exceptions import ( LicenseActivationMissingError, LicenseToActivateIsRevokedError, @@ -150,8 +151,16 @@ class CustomerAgreement(TimeStampedModel): ) ) - expired_subscription_modal_messaging = models.CharField( + modal_header_text = models.CharField( max_length=512, + blank=True, + null=True, + help_text=_( + "The bold text that will appear as the header in the expiration modal." + ) + ) + + expired_subscription_modal_messaging = models.TextField( blank=True, null=True, help_text=_( @@ -160,21 +169,21 @@ class CustomerAgreement(TimeStampedModel): ) ) - hyper_link_text_for_expired_modal = models.CharField( + button_label_in_modal = models.CharField( max_length=255, blank=True, null=True, help_text=_( - "The display text for the link that will be embedded at the end of the custom expiration modal." + "The text that will appear as on the button in the expiration modal" ) ) - url_for_expired_modal = models.CharField( + url_for_button_in_modal = models.CharField( max_length=512, blank=True, null=True, help_text=_( - "The underlying url that will be embedded as a hyperlink at the end of the custom expiration modal." + "The URL that should underly the sole button in the expiration modal" ) ) @@ -237,54 +246,55 @@ class Meta: verbose_name_plural = _("Customer Agreements") def clean(self): - # Check if custom messaging is enabled and messaging field is blank + """ + Custom clean method to validate fields based on the 'Has Custom License Expiration Messaging' flag. + """ + errors = {} + + # Sanitize the expired_subscription_modal_messaging field + if self.expired_subscription_modal_messaging: + self.expired_subscription_modal_messaging = sanitize_html(self.expired_subscription_modal_messaging) + + error_message = "This field cannot be blank if 'Has Custom License Expiration Messaging' is checked." + # Validate fields when custom messaging is enabled if self.has_custom_license_expiration_messaging: - if not self.expired_subscription_modal_messaging: - raise ValidationError({ - "expired_subscription_modal_messaging": ( - "This field cannot be blank if 'Has Custom License Expiration Messaging' is checked." - ) - }) - - # Validate that URL field is not blank if hyperlink text is provided - if self.hyper_link_text_for_expired_modal and not self.url_for_expired_modal: - raise ValidationError({ - "url_for_expired_modal": ( - "This field cannot be blank if 'Hyper Link Text for Expired Modal' has values." - ) - }) + required_fields = { + "modal_header_text": error_message, + "expired_subscription_modal_messaging": error_message, + "button_label_in_modal": error_message, + "url_for_button_in_modal": error_message, + } - # Validate that hyperlink text is not blank if URL is provided - if self.url_for_expired_modal and not self.hyper_link_text_for_expired_modal: - raise ValidationError({ - "hyper_link_text_for_expired_modal": ( - "This field cannot be blank if 'URL for Expired Modal' has values." - ) - }) + # Check if any required fields are missing + for field, error_message in required_fields.items(): + if not getattr(self, field): + errors[field] = error_message # Ensure all fields are blank if custom messaging is disabled if not self.has_custom_license_expiration_messaging: - if any([ - self.expired_subscription_modal_messaging, - self.hyper_link_text_for_expired_modal, - self.url_for_expired_modal - ]): + fields_to_check = [ + "modal_header_text", + "expired_subscription_modal_messaging", + "button_label_in_modal", + "url_for_button_in_modal" + ] + if any(getattr(self, field) for field in fields_to_check): error_msg = "This field must be blank if 'Has Custom License Expiration Messaging' is unchecked." - raise ValidationError({ - "expired_subscription_modal_messaging": error_msg, - "hyper_link_text_for_expired_modal": error_msg, - "url_for_expired_modal": error_msg, - }) - - def __str__(self): - """ - Return human-readable string representation. - """ - return ( - "".format( - self.enterprise_customer_slug or self.enterprise_customer_name - ) + errors = {field: error_msg for field in fields_to_check} + + # Raise ValidationError if there are any errors + if errors: + raise ValidationError(errors) + + def __str__(self): + """ + Return human-readable string representation. + """ + return ( + "".format( + self.enterprise_customer_slug or self.enterprise_customer_name ) + ) class PlanType(models.Model): diff --git a/license_manager/apps/subscriptions/sanitize.py b/license_manager/apps/subscriptions/sanitize.py new file mode 100644 index 00000000..c2da423b --- /dev/null +++ b/license_manager/apps/subscriptions/sanitize.py @@ -0,0 +1,30 @@ +import bleach + + +def sanitize_html(html_content): + """ + Sanitize HTML content to allow only safe tags and attributes, + while disallowing JavaScript and unsafe protocols. + """ + # Define allowed tags and attributes + allowed_tags = bleach.ALLOWED_TAGS # Allow all standard HTML tags + allowed_attrs = {"*": ["className", "class", "style", "id"]} + + # Clean the HTML content + sanitized_content = bleach.clean( + html_content, + tags=allowed_tags, + attributes=allowed_attrs, + strip=True, # Strip disallowed tags completely + protocols=["http", "https"], # Only allow http and https URLs + ) + + # Use bleach.linkify to ensure no javascript: links in tags + sanitized_content = bleach.linkify( + sanitized_content, + callbacks=[ + bleach.callbacks.nofollow + ], # Apply 'nofollow' to external links for safety + ) + + return sanitized_content diff --git a/requirements/base.in b/requirements/base.in index e7bdd14f..6de2a2d5 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -40,3 +40,4 @@ rules simplejson zipp django-log-request-id +bleach diff --git a/requirements/base.txt b/requirements/base.txt index 8c3f77b4..2358c024 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -22,9 +22,11 @@ backoff==1.10.0 # analytics-python billiard==4.2.1 # via celery -boto3==1.35.34 +bleach==6.1.0 + # via -r requirements/base.in +boto3==1.35.41 # via django-ses -botocore==1.35.34 +botocore==1.35.41 # via # boto3 # s3transfer @@ -39,7 +41,7 @@ cffi==1.17.1 # via # cryptography # pynacl -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via requests click==8.1.7 # via @@ -97,7 +99,7 @@ django-autocomplete-light==3.11.0 # via -r requirements/base.in django-celery-results==2.5.1 # via -r requirements/base.in -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # via -r requirements/base.in django-crum==0.7.9 # via @@ -153,7 +155,7 @@ edx-braze-client==0.2.5 # via -r requirements/base.in edx-celeryutils==1.3.0 # via -r requirements/base.in -edx-django-utils==5.16.0 +edx-django-utils==6.1.0 # via # -r requirements/base.in # edx-drf-extensions @@ -185,17 +187,17 @@ jsonfield==3.1.0 # via edx-celeryutils jsonschema==4.23.0 # via drf-spectacular -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via jsonschema kombu==5.4.2 # via celery -markupsafe==2.1.5 +markupsafe==3.0.1 # via jinja2 monotonic==1.6 # via analytics-python mysqlclient==2.2.4 # via -r requirements/base.in -newrelic==10.0.0 +newrelic==10.2.0 # via edx-django-utils oauthlib==3.2.2 # via @@ -258,7 +260,7 @@ rpds-py==0.20.0 # referencing rules==3.5 # via -r requirements/base.in -s3transfer==0.10.2 +s3transfer==0.10.3 # via boto3 semantic-version==2.10.0 # via edx-drf-extensions @@ -267,6 +269,7 @@ simplejson==3.19.3 six==1.16.0 # via # analytics-python + # bleach # edx-auth-backends # edx-rbac # python-dateutil @@ -304,6 +307,8 @@ vine==5.1.0 # kombu wcwidth==0.2.13 # via prompt-toolkit +webencodings==0.5.1 + # via bleach zipp==3.20.2 # via -r requirements/base.in diff --git a/requirements/dev.txt b/requirements/dev.txt index 6101d291..995c1f17 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -33,11 +33,13 @@ billiard==4.2.1 # via # -r requirements/validation.txt # celery -boto3==1.35.34 +bleach==6.1.0 + # via -r requirements/validation.txt +boto3==1.35.41 # via # -r requirements/validation.txt # django-ses -botocore==1.35.34 +botocore==1.35.41 # via # -r requirements/validation.txt # boto3 @@ -60,7 +62,7 @@ cffi==1.17.1 # -r requirements/validation.txt # cryptography # pynacl -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via # -r requirements/validation.txt # requests @@ -98,7 +100,7 @@ code-annotations==1.8.0 # -r requirements/validation.txt # edx-lint # edx-toggles -coverage[toml]==7.6.1 +coverage[toml]==7.6.3 # via # -r requirements/validation.txt # pytest-cov @@ -158,7 +160,7 @@ django-autocomplete-light==3.11.0 # via -r requirements/validation.txt django-celery-results==2.5.1 # via -r requirements/validation.txt -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # via -r requirements/validation.txt django-crum==0.7.9 # via @@ -225,7 +227,7 @@ edx-braze-client==0.2.5 # via -r requirements/validation.txt edx-celeryutils==1.3.0 # via -r requirements/validation.txt -edx-django-utils==5.16.0 +edx-django-utils==6.1.0 # via # -r requirements/validation.txt # edx-drf-extensions @@ -251,7 +253,7 @@ edx-toggles==5.2.0 # via -r requirements/validation.txt factory-boy==3.3.1 # via -r requirements/validation.txt -faker==30.1.0 +faker==30.4.0 # via # -r requirements/validation.txt # factory-boy @@ -300,7 +302,7 @@ jsonschema==4.23.0 # via # -r requirements/validation.txt # drf-spectacular -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via # -r requirements/validation.txt # jsonschema @@ -313,11 +315,11 @@ lxml[html-clean]==5.3.0 # -r requirements/validation.txt # edx-i18n-tools # lxml-html-clean -lxml-html-clean==0.2.2 +lxml-html-clean==0.3.1 # via # -r requirements/validation.txt # lxml -markupsafe==2.1.5 +markupsafe==3.0.1 # via # -r requirements/validation.txt # jinja2 @@ -333,7 +335,7 @@ more-itertools==10.5.0 # via inflect mysqlclient==2.2.4 # via -r requirements/validation.txt -newrelic==10.0.0 +newrelic==10.2.0 # via # -r requirements/validation.txt # edx-django-utils @@ -416,7 +418,7 @@ pylint-celery==0.3 # via # -r requirements/validation.txt # edx-lint -pylint-django==2.5.5 +pylint-django==2.6.1 # via # -r requirements/validation.txt # edx-lint @@ -499,7 +501,7 @@ rpds-py==0.20.0 # referencing rules==3.5 # via -r requirements/validation.txt -s3transfer==0.10.2 +s3transfer==0.10.3 # via # -r requirements/validation.txt # boto3 @@ -513,6 +515,7 @@ six==1.16.0 # via # -r requirements/validation.txt # analytics-python + # bleach # edx-auth-backends # edx-lint # edx-rbac @@ -582,6 +585,10 @@ wcwidth==0.2.13 # via # -r requirements/validation.txt # prompt-toolkit +webencodings==0.5.1 + # via + # -r requirements/validation.txt + # bleach wheel==0.44.0 # via # -r requirements/pip-tools.txt diff --git a/requirements/doc.txt b/requirements/doc.txt index 662ea20b..dd901103 100644 --- a/requirements/doc.txt +++ b/requirements/doc.txt @@ -43,11 +43,13 @@ billiard==4.2.1 # via # -r requirements/test.txt # celery -boto3==1.35.34 +bleach==6.1.0 + # via -r requirements/test.txt +boto3==1.35.41 # via # -r requirements/test.txt # django-ses -botocore==1.35.34 +botocore==1.35.41 # via # -r requirements/test.txt # boto3 @@ -66,7 +68,7 @@ cffi==1.17.1 # -r requirements/test.txt # cryptography # pynacl -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via # -r requirements/test.txt # requests @@ -102,7 +104,7 @@ code-annotations==1.8.0 # -r requirements/test.txt # edx-lint # edx-toggles -coverage[toml]==7.6.1 +coverage[toml]==7.6.3 # via # -r requirements/test.txt # pytest-cov @@ -154,7 +156,7 @@ django-autocomplete-light==3.11.0 # via -r requirements/test.txt django-celery-results==2.5.1 # via -r requirements/test.txt -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # via -r requirements/test.txt django-crum==0.7.9 # via @@ -226,7 +228,7 @@ edx-braze-client==0.2.5 # via -r requirements/test.txt edx-celeryutils==1.3.0 # via -r requirements/test.txt -edx-django-utils==5.16.0 +edx-django-utils==6.1.0 # via # -r requirements/test.txt # edx-drf-extensions @@ -250,7 +252,7 @@ edx-toggles==5.2.0 # via -r requirements/test.txt factory-boy==3.3.1 # via -r requirements/test.txt -faker==30.1.0 +faker==30.4.0 # via # -r requirements/test.txt # factory-boy @@ -292,7 +294,7 @@ jsonschema==4.23.0 # via # -r requirements/test.txt # drf-spectacular -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via # -r requirements/test.txt # jsonschema @@ -300,7 +302,7 @@ kombu==5.4.2 # via # -r requirements/test.txt # celery -markupsafe==2.1.5 +markupsafe==3.0.1 # via # -r requirements/test.txt # jinja2 @@ -314,7 +316,7 @@ monotonic==1.6 # analytics-python mysqlclient==2.2.4 # via -r requirements/test.txt -newrelic==10.0.0 +newrelic==10.2.0 # via # -r requirements/test.txt # edx-django-utils @@ -387,7 +389,7 @@ pylint-celery==0.3 # via # -r requirements/test.txt # edx-lint -pylint-django==2.5.5 +pylint-django==2.6.1 # via # -r requirements/test.txt # edx-lint @@ -467,7 +469,7 @@ rpds-py==0.20.0 # referencing rules==3.5 # via -r requirements/test.txt -s3transfer==0.10.2 +s3transfer==0.10.3 # via # -r requirements/test.txt # boto3 @@ -481,6 +483,7 @@ six==1.16.0 # via # -r requirements/test.txt # analytics-python + # bleach # edx-auth-backends # edx-lint # edx-rbac @@ -498,7 +501,7 @@ social-auth-core==4.5.4 # social-auth-app-django soupsieve==2.6 # via beautifulsoup4 -sphinx==8.0.2 +sphinx==8.1.3 # via # -r requirements/doc.in # pydata-sphinx-theme @@ -566,6 +569,10 @@ wcwidth==0.2.13 # via # -r requirements/test.txt # prompt-toolkit +webencodings==0.5.1 + # via + # -r requirements/test.txt + # bleach zipp==3.20.2 # via -r requirements/test.txt diff --git a/requirements/pip.txt b/requirements/pip.txt index 488d41f8..35655630 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -10,5 +10,5 @@ wheel==0.44.0 # The following packages are considered to be unsafe in a requirements file: pip==24.2 # via -r requirements/pip.in -setuptools==75.1.0 +setuptools==75.2.0 # via -r requirements/pip.in diff --git a/requirements/production.txt b/requirements/production.txt index 1a3d85d0..66c34001 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -28,11 +28,13 @@ billiard==4.2.1 # via # -r requirements/base.txt # celery -boto3==1.35.34 +bleach==6.1.0 + # via -r requirements/base.txt +boto3==1.35.41 # via # -r requirements/base.txt # django-ses -botocore==1.35.34 +botocore==1.35.41 # via # -r requirements/base.txt # boto3 @@ -51,7 +53,7 @@ cffi==1.17.1 # -r requirements/base.txt # cryptography # pynacl -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via # -r requirements/base.txt # requests @@ -122,7 +124,7 @@ django-autocomplete-light==3.11.0 # via -r requirements/base.txt django-celery-results==2.5.1 # via -r requirements/base.txt -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # via -r requirements/base.txt django-crum==0.7.9 # via @@ -183,7 +185,7 @@ edx-braze-client==0.2.5 # via -r requirements/base.txt edx-celeryutils==1.3.0 # via -r requirements/base.txt -edx-django-utils==5.16.0 +edx-django-utils==6.1.0 # via # -r requirements/base.txt # edx-drf-extensions @@ -203,7 +205,7 @@ edx-rest-api-client==6.0.0 # via -r requirements/base.txt edx-toggles==5.2.0 # via -r requirements/base.txt -gevent==24.2.1 +gevent==24.10.2 # via -r requirements/production.in greenlet==3.1.1 # via gevent @@ -234,7 +236,7 @@ jsonschema==4.23.0 # via # -r requirements/base.txt # drf-spectacular -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via # -r requirements/base.txt # jsonschema @@ -242,7 +244,7 @@ kombu==5.4.2 # via # -r requirements/base.txt # celery -markupsafe==2.1.5 +markupsafe==3.0.1 # via # -r requirements/base.txt # jinja2 @@ -252,7 +254,7 @@ monotonic==1.6 # analytics-python mysqlclient==2.2.4 # via -r requirements/base.txt -newrelic==10.0.0 +newrelic==10.2.0 # via # -r requirements/base.txt # edx-django-utils @@ -351,7 +353,7 @@ rpds-py==0.20.0 # referencing rules==3.5 # via -r requirements/base.txt -s3transfer==0.10.2 +s3transfer==0.10.3 # via # -r requirements/base.txt # boto3 @@ -365,6 +367,7 @@ six==1.16.0 # via # -r requirements/base.txt # analytics-python + # bleach # edx-auth-backends # edx-rbac # python-dateutil @@ -419,11 +422,15 @@ wcwidth==0.2.13 # via # -r requirements/base.txt # prompt-toolkit +webencodings==0.5.1 + # via + # -r requirements/base.txt + # bleach zipp==3.20.2 # via -r requirements/base.txt zope-event==5.0 # via gevent -zope-interface==7.0.3 +zope-interface==7.1.0 # via gevent # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/quality.txt b/requirements/quality.txt index 7f267c8a..7fe4d6b1 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -32,11 +32,13 @@ billiard==4.2.1 # via # -r requirements/base.txt # celery -boto3==1.35.34 +bleach==6.1.0 + # via -r requirements/base.txt +boto3==1.35.41 # via # -r requirements/base.txt # django-ses -botocore==1.35.34 +botocore==1.35.41 # via # -r requirements/base.txt # boto3 @@ -55,7 +57,7 @@ cffi==1.17.1 # -r requirements/base.txt # cryptography # pynacl -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via # -r requirements/base.txt # requests @@ -133,7 +135,7 @@ django-autocomplete-light==3.11.0 # via -r requirements/base.txt django-celery-results==2.5.1 # via -r requirements/base.txt -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # via -r requirements/base.txt django-crum==0.7.9 # via @@ -194,7 +196,7 @@ edx-braze-client==0.2.5 # via -r requirements/base.txt edx-celeryutils==1.3.0 # via -r requirements/base.txt -edx-django-utils==5.16.0 +edx-django-utils==6.1.0 # via # -r requirements/base.txt # edx-drf-extensions @@ -245,7 +247,7 @@ jsonschema==4.23.0 # via # -r requirements/base.txt # drf-spectacular -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via # -r requirements/base.txt # jsonschema @@ -253,7 +255,7 @@ kombu==5.4.2 # via # -r requirements/base.txt # celery -markupsafe==2.1.5 +markupsafe==3.0.1 # via # -r requirements/base.txt # jinja2 @@ -265,7 +267,7 @@ monotonic==1.6 # analytics-python mysqlclient==2.2.4 # via -r requirements/base.txt -newrelic==10.0.0 +newrelic==10.2.0 # via # -r requirements/base.txt # edx-django-utils @@ -316,7 +318,7 @@ pylint==3.3.1 # pylint-plugin-utils pylint-celery==0.3 # via edx-lint -pylint-django==2.5.5 +pylint-django==2.6.1 # via edx-lint pylint-plugin-utils==0.8.2 # via @@ -377,7 +379,7 @@ rpds-py==0.20.0 # referencing rules==3.5 # via -r requirements/base.txt -s3transfer==0.10.2 +s3transfer==0.10.3 # via # -r requirements/base.txt # boto3 @@ -391,6 +393,7 @@ six==1.16.0 # via # -r requirements/base.txt # analytics-python + # bleach # edx-auth-backends # edx-lint # edx-rbac @@ -450,6 +453,10 @@ wcwidth==0.2.13 # via # -r requirements/base.txt # prompt-toolkit +webencodings==0.5.1 + # via + # -r requirements/base.txt + # bleach zipp==3.20.2 # via -r requirements/base.txt diff --git a/requirements/test.txt b/requirements/test.txt index ec8e86c9..dcae5482 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -32,11 +32,13 @@ billiard==4.2.1 # via # -r requirements/base.txt # celery -boto3==1.35.34 +bleach==6.1.0 + # via -r requirements/base.txt +boto3==1.35.41 # via # -r requirements/base.txt # django-ses -botocore==1.35.34 +botocore==1.35.41 # via # -r requirements/base.txt # boto3 @@ -55,7 +57,7 @@ cffi==1.17.1 # -r requirements/base.txt # cryptography # pynacl -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via # -r requirements/base.txt # requests @@ -90,7 +92,7 @@ code-annotations==1.8.0 # -r requirements/test.in # edx-lint # edx-toggles -coverage[toml]==7.6.1 +coverage[toml]==7.6.3 # via # -r requirements/test.in # pytest-cov @@ -140,7 +142,7 @@ django-autocomplete-light==3.11.0 # via -r requirements/base.txt django-celery-results==2.5.1 # via -r requirements/base.txt -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # via -r requirements/base.txt django-crum==0.7.9 # via @@ -203,7 +205,7 @@ edx-braze-client==0.2.5 # via -r requirements/base.txt edx-celeryutils==1.3.0 # via -r requirements/base.txt -edx-django-utils==5.16.0 +edx-django-utils==6.1.0 # via # -r requirements/base.txt # edx-drf-extensions @@ -227,7 +229,7 @@ edx-toggles==5.2.0 # via -r requirements/base.txt factory-boy==3.3.1 # via -r requirements/test.in -faker==30.1.0 +faker==30.4.0 # via factory-boy freezegun==1.5.1 # via -r requirements/test.in @@ -260,7 +262,7 @@ jsonschema==4.23.0 # via # -r requirements/base.txt # drf-spectacular -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via # -r requirements/base.txt # jsonschema @@ -268,7 +270,7 @@ kombu==5.4.2 # via # -r requirements/base.txt # celery -markupsafe==2.1.5 +markupsafe==3.0.1 # via # -r requirements/base.txt # jinja2 @@ -280,7 +282,7 @@ monotonic==1.6 # analytics-python mysqlclient==2.2.4 # via -r requirements/base.txt -newrelic==10.0.0 +newrelic==10.2.0 # via # -r requirements/base.txt # edx-django-utils @@ -331,7 +333,7 @@ pylint==3.3.1 # pylint-plugin-utils pylint-celery==0.3 # via edx-lint -pylint-django==2.5.5 +pylint-django==2.6.1 # via edx-lint pylint-plugin-utils==0.8.2 # via @@ -402,7 +404,7 @@ rpds-py==0.20.0 # referencing rules==3.5 # via -r requirements/base.txt -s3transfer==0.10.2 +s3transfer==0.10.3 # via # -r requirements/base.txt # boto3 @@ -416,6 +418,7 @@ six==1.16.0 # via # -r requirements/base.txt # analytics-python + # bleach # edx-auth-backends # edx-lint # edx-rbac @@ -474,6 +477,10 @@ wcwidth==0.2.13 # via # -r requirements/base.txt # prompt-toolkit +webencodings==0.5.1 + # via + # -r requirements/base.txt + # bleach zipp==3.20.2 # via -r requirements/base.txt diff --git a/requirements/validation.txt b/requirements/validation.txt index 9d79f3ef..ff942015 100644 --- a/requirements/validation.txt +++ b/requirements/validation.txt @@ -41,12 +41,16 @@ billiard==4.2.1 # -r requirements/quality.txt # -r requirements/test.txt # celery -boto3==1.35.34 +bleach==6.1.0 + # via + # -r requirements/quality.txt + # -r requirements/test.txt +boto3==1.35.41 # via # -r requirements/quality.txt # -r requirements/test.txt # django-ses -botocore==1.35.34 +botocore==1.35.41 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -69,7 +73,7 @@ cffi==1.17.1 # -r requirements/test.txt # cryptography # pynacl -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -112,7 +116,7 @@ code-annotations==1.8.0 # -r requirements/test.txt # edx-lint # edx-toggles -coverage[toml]==7.6.1 +coverage[toml]==7.6.3 # via # -r requirements/test.txt # pytest-cov @@ -173,7 +177,7 @@ django-celery-results==2.5.1 # via # -r requirements/quality.txt # -r requirements/test.txt -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -270,7 +274,7 @@ edx-celeryutils==1.3.0 # via # -r requirements/quality.txt # -r requirements/test.txt -edx-django-utils==5.16.0 +edx-django-utils==6.1.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -307,7 +311,7 @@ edx-toggles==5.2.0 # -r requirements/test.txt factory-boy==3.3.1 # via -r requirements/test.txt -faker==30.1.0 +faker==30.4.0 # via # -r requirements/test.txt # factory-boy @@ -353,7 +357,7 @@ jsonschema==4.23.0 # -r requirements/quality.txt # -r requirements/test.txt # drf-spectacular -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -367,9 +371,9 @@ lxml[html-clean,html_clean]==5.3.0 # via # edx-i18n-tools # lxml-html-clean -lxml-html-clean==0.2.2 +lxml-html-clean==0.3.1 # via lxml -markupsafe==2.1.5 +markupsafe==3.0.1 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -388,7 +392,7 @@ mysqlclient==2.2.4 # via # -r requirements/quality.txt # -r requirements/test.txt -newrelic==10.0.0 +newrelic==10.2.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -471,7 +475,7 @@ pylint-celery==0.3 # -r requirements/quality.txt # -r requirements/test.txt # edx-lint -pylint-django==2.5.5 +pylint-django==2.6.1 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -565,7 +569,7 @@ rules==3.5 # via # -r requirements/quality.txt # -r requirements/test.txt -s3transfer==0.10.2 +s3transfer==0.10.3 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -584,6 +588,7 @@ six==1.16.0 # -r requirements/quality.txt # -r requirements/test.txt # analytics-python + # bleach # edx-auth-backends # edx-lint # edx-rbac @@ -661,6 +666,11 @@ wcwidth==0.2.13 # -r requirements/quality.txt # -r requirements/test.txt # prompt-toolkit +webencodings==0.5.1 + # via + # -r requirements/quality.txt + # -r requirements/test.txt + # bleach zipp==3.20.2 # via # -r requirements/quality.txt