Skip to content

Conversation

@19vip
Copy link

@19vip 19vip commented Dec 18, 2025

Summary

This PR replaces the custom password length check in the change password endpoint with Django’s built-in password validation framework.

Problem:
The change password API previously enforced only a minimal custom length check, allowing weak passwords and ignoring project-configured password rules.

Solution:
Uses Django’s validate_password with user context to apply all configured validators.
Returns proper DRF validation errors when password rules are violated.
Preserves existing API behavior without breaking changes.

Impact:
Improves password security by aligning with Django standards.
Ensures consistent validation across the application.

Scope:
Backend only
No database changes
No API breaking changes

Summary by CodeRabbit

  • Bug Fixes
    • Strengthened password validation when changing passwords — users will receive clearer, actionable error messages for password requirements (including minimum strength and other account-specific rules).
    • Added an explicit maximum password length (128 characters) to prevent overly long submissions.
    • Fixed an issue ensuring submitted new passwords are properly validated and applied during change operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@19vip 19vip requested a review from a team as a code owner December 18, 2025 12:38
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 18, 2025

📝 Walkthrough

Walkthrough

Removed the serializer docstring, constrained new_password to max_length=128, added validate_new_password(self, value) on the serializer that calls Django's validate_password (mapping DjangoValidationError to DRF serializers.ValidationError), added imports for validate_password and ValidationError as DjangoValidationError, and switched password assignment to use serializer.validated_data.get("new_password").

Changes

Cohort / File(s) Summary
ChangePassword serializer & validator
care/users/api/viewsets/change_password.py
Removed class docstring; changed new_password from CharField(required=True) to CharField(required=True, max_length=128); added validate_new_password(self, value) on the serializer which calls validate_password(value, user=...), catches DjangoValidationError and raises DRF serializers.ValidationError; added imports for validate_password and ValidationError as DjangoValidationError; update flow to use serializer.validated_data.get("new_password") when setting the password.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Review focus:
    • Ensure validate_new_password(self, value) is placed on the serializer and correctly accesses self.context["request"].user.
    • Verify error mapping preserves message structure for DRF consumers.
    • Confirm max_length=128 aligns with project constraints and no unused imports remain.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ⚠️ Warning The PR description lacks required sections from the template: no Associated Issue link, no Architecture changes section, and the Merge Checklist is completely missing. Add the Associated Issue section with a link to the GitHub issue, include the Merge Checklist with test/lint status, and optionally add Architecture changes if applicable to this refactor.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Enforce Django password validation on password change' accurately summarizes the main change: implementing Django's built-in password validators for the password change endpoint.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
care/users/api/viewsets/change_password.py (2)

10-10: Restore the removed docstring for better maintainability.

The class docstring was removed in this change. Documentation helps maintain code clarity, especially for serializers that handle security-sensitive operations.

🔎 Add a docstring to the serializer:
 class ChangePasswordSerializer(serializers.Serializer):
+    """
+    Serializer for changing user password with validation.
+    """
     old_password = serializers.CharField(required=True)

31-50: Verify the validation works as expected and add tests.

The PR objectives mention that tests were not added for this security-related change. Please ensure that:

  1. Passwords shorter than 8 characters are properly rejected with clear error messages
  2. Passwords exactly 8 characters long are accepted
  3. Edge cases like empty strings, whitespace, and special characters are handled correctly
  4. The API response format remains consistent with existing patterns

Would you like me to help generate test cases for this validation change?

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 59d74d8 and 6c79056.

📒 Files selected for processing (1)
  • care/users/api/viewsets/change_password.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursorrules)

**/*.py: Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance).
Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).

Files:

  • care/users/api/viewsets/change_password.py

@19vip
Copy link
Author

19vip commented Dec 18, 2025

Hi maintainers 👋
This is my first contribution to OHC.
Happy to make any changes or improvements if required.
Thanks for reviewing!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
care/users/api/viewsets/change_password.py (1)

14-14: Consider adding help_text for better API documentation.

While the field definition is technically correct, adding a help_text (e.g., "Password must meet security requirements.") would make the API more self-documenting for consumers.

🔎 View suggested enhancement:
-    new_password = serializers.CharField(required=True, max_length=128)
+    new_password = serializers.CharField(
+        required=True,
+        max_length=128,
+        help_text="Password must meet security requirements.",
+    )
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c79056 and 298aa4c.

📒 Files selected for processing (1)
  • care/users/api/viewsets/change_password.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursorrules)

**/*.py: Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance).
Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).

Files:

  • care/users/api/viewsets/change_password.py
🪛 Ruff (0.14.8)
care/users/api/viewsets/change_password.py

20-20: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🔇 Additional comments (1)
care/users/api/viewsets/change_password.py (1)

2-3: LGTM!

The imports are correctly added and the aliasing of DjangoValidationError properly avoids conflicts with DRF's ValidationError.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
care/users/api/viewsets/change_password.py (3)

14-14: Consider adding explicit min_length=8 for clarity.

While Django's MinimumLengthValidator (called in validate_new_password) enforces the 8-character minimum by default, adding min_length=8 to the field definition would make the constraint immediately visible and provide a faster fail path before the more expensive Django validation runs. It also documents the requirement at the field level, which is, you know, kind of helpful for anyone reading the code.

🔎 Proposed enhancement
-    new_password = serializers.CharField(required=True, max_length=128)
+    new_password = serializers.CharField(required=True, min_length=8, max_length=128)

16-22: Add defensive context access to prevent KeyError.

Line 17 uses direct dictionary access self.context["request"] which will raise a KeyError if the serializer is instantiated without request context (e.g., in tests, management commands, or other contexts). While it works fine in the current UpdateAPIView usage, it makes the serializer unnecessarily fragile for reuse.

🔎 Proposed fix with defensive access
     def validate_new_password(self, value):
-        user = self.context["request"].user
+        request = self.context.get("request")
+        user = request.user if request else None
         try:
             validate_password(value, user=user)
         except DjangoValidationError as e:
             raise serializers.ValidationError(e.messages) from e
         return value

16-22: Add tests for the new password validation logic.

The PR objectives mention that tests were "not added in this PR," but password validation is security-critical functionality that really should have test coverage. Without tests, there's no verification that the Django validators are working as expected or that the error messages are properly formatted for the API response.

Would you like me to generate test cases covering various scenarios (weak passwords, user attribute similarity, numeric-only passwords, etc.)?

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4322e3 and 2bbf495.

📒 Files selected for processing (1)
  • care/users/api/viewsets/change_password.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursorrules)

**/*.py: Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance).
Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).

Files:

  • care/users/api/viewsets/change_password.py
🧬 Code graph analysis (1)
care/users/api/viewsets/change_password.py (1)
care/emr/resources/user/spec.py (1)
  • validate_password (110-117)
🔇 Additional comments (2)
care/users/api/viewsets/change_password.py (2)

2-3: LGTM! Clean import structure.

The imports are well-organized and the aliasing of ValidationError as DjangoValidationError properly avoids naming conflicts with DRF's validation error.


52-52: Excellent fix using validated_data instead of data.

This correctly uses the cleaned and validated password from validated_data rather than the raw input from data. This ensures all validation (including the new Django password validators) is properly applied before the password is set.

@19vip 19vip changed the title Add minimum password length validation Enforce Django password validation on password change Dec 23, 2025
@19vip
Copy link
Author

19vip commented Dec 26, 2025

Thanks for the review @sainak!
I’ll keep an eye on this area and follow up with tests / related improvements if needed.

@19vip
Copy link
Author

19vip commented Dec 26, 2025

While adding tests for this, I noticed a few issues in the validation flow. I’ve fixed them and added full test coverage in PR #3434, which replaces this one. Please check that PR instead. Thanks!

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.

2 participants