Skip to content

Conversation

@19vip
Copy link

@19vip 19vip commented Dec 26, 2025

Proposed Changes

  • Enforced Django's built-in password validation for the change-password endpoint.
  • Added comprehensive regression tests covering weak passwords, incorrect current password, and successful password update scenarios.
  • Preserved exception chaining for better debugging context.

Associated Issue

N/A

Merge Checklist

  • Tests added / updated
  • Local tests passing
  • No breaking changes
  • Backward compatible
  • Code formatted and linted

cc: @ohcnetwork/care-backend-admins

Summary by CodeRabbit

  • Improvements

    • Enforced Django password validation on password changes and clarified validation error responses; preserved current-password checks and streamlined the update flow.
  • Tests

    • Added tests for the change-password endpoint covering weak-password rejection, incorrect current password, and successful password updates.

✏️ 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 26, 2025 05:34
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 26, 2025

📝 Walkthrough

Walkthrough

Adds Django password validation to the change-password serializer, refactors validation flow to use DRF's is_valid(raise_exception=True), adjusts update logic to set_password and save, and introduces tests verifying weak-password rejection, wrong-old-password handling, and successful password change.

Changes

Cohort / File(s) Summary
Password validation & endpoint logic
care/users/api/viewsets/change_password.py
Added validate_new_password() to ChangePasswordSerializer to run Django validate_password and convert DjangoValidationError into DRF ValidationError. Switched to serializer.is_valid(raise_exception=True), use serializer.validated_data, check old_password with object.check_password, then set_password and save. Minor docstring tweaks.
Tests for change-password
care/users/tests/test_change_password.py
Added tests: test_weak_password_is_rejected, test_wrong_old_password_fails, test_password_change_success. Tests authenticate a user, call the change-password endpoint, assert status codes and error keys, and verify persisted password change.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: enforcing password validation and adding comprehensive regression tests.
Description check ✅ Passed The description covers proposed changes and includes a merge checklist, though it deviates from the template structure by omitting the optional 'Architecture changes' section and documentation updates.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
✨ 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

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61717cd and f709b0e.

📒 Files selected for processing (2)
  • care/users/api/viewsets/change_password.py
  • care/users/tests/test_change_password.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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
  • care/users/tests/test_change_password.py
**/tests/**/*.py

📄 CodeRabbit inference engine (.cursorrules)

Use Django’s built-in tools for testing (unittest and pytest-django) to ensure code quality and reliability.

Files:

  • care/users/tests/test_change_password.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: ohcnetwork/care PR: 0
File: .cursorrules:0-0
Timestamp: 2025-07-18T15:17:40.483Z
Learning: Apply Django's security best practices (e.g., CSRF protection, SQL injection protection, XSS prevention).
🧬 Code graph analysis (2)
care/users/api/viewsets/change_password.py (2)
care/emr/resources/user/spec.py (1)
  • validate_password (110-117)
care/users/models.py (1)
  • User (96-212)
care/users/tests/test_change_password.py (2)
care/users/models.py (1)
  • User (96-212)
care/utils/tests/base.py (1)
  • create_user (25-28)
🪛 Ruff (0.14.10)
care/users/api/viewsets/change_password.py

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

(B904)


33-33: Unused method argument: args

(ARG002)


33-33: Unused method argument: kwargs

(ARG002)

care/users/tests/test_change_password.py

13-13: Possible hardcoded password assigned to argument: "password"

(S106)

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

2-3: LGTM! Imports align with Django's validation framework.

The imports are appropriate for integrating Django's password validation into the serializer.


36-36: Excellent! Core security fix enforces validation.

Adding raise_exception=True ensures that validation failures are consistently caught and returned to the client, preventing weak passwords from slipping through. This directly addresses the security gap mentioned in the PR objectives.


38-52: LGTM! Clean refactoring with validated_data.

The update logic correctly uses validated_data after validation, maintaining the existing behavior while integrating with the new validation flow. The old password check and error response structure remain intact.

care/users/tests/test_change_password.py (4)

1-16: LGTM! Well-structured test setup.

The setup follows Django testing best practices with proper user creation, authentication, and URL resolution. The test user password ("StrongPass@123") is appropriately strong for testing validation scenarios.


18-28: LGTM! Comprehensive weak password validation test.

This test effectively verifies that Django's password validators reject weak passwords and return the appropriate error response. The assertion on new_password being in the error keys ensures the validation is properly attributed to the correct field.


30-38: LGTM! Proper verification of old password check.

This test ensures that users must provide the correct current password to change it. The assertions correctly verify both the status code and the error field, which aligns with the expected behavior in the view.


40-51: LGTM! Thorough verification of successful password change.

This test excellently verifies the complete flow, including the critical step of confirming that the password is actually persisted in the database. The use of refresh_from_db() followed by check_password() ensures the change isn't just a response facade but a genuine database update.

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 (1)
care/users/api/viewsets/change_password.py (1)

22-31: Good work addressing the exception chaining feedback.

The validation method correctly uses Django's password validators and now properly preserves the exception chain with from e. This implementation follows Django best practices.

One optional consideration: you might want to validate that the new password differs from the old password, though this is not strictly required by Django and can be deferred if not needed.

💡 Optional enhancement: reject identical passwords
 def validate_new_password(self, value):
     """
     Validate the new password against Django's password policies.
     """
     user = self.context["request"].user
+    if user.check_password(value):
+        raise serializers.ValidationError(
+            "New password must be different from the current password."
+        )
     try:
         validate_password(value, user=user)
     except DjangoValidationError as e:
         raise serializers.ValidationError(e.messages) from e
     return value
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d69ee3b and f9a11c6.

📒 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)
🪛 Ruff (0.14.10)
care/users/api/viewsets/change_password.py

46-46: Unused method argument: args

(ARG002)


46-46: Unused method argument: kwargs

(ARG002)

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

2-3: LGTM! Imports are appropriate for Django password validation.

The necessary imports are in place for the new validation logic.


13-17: LGTM! Clear and informative docstring.

The updated docstring accurately describes the serializer's validation behavior.


40-40: LGTM! Docstring is clear.


47-49: LGTM! Method documentation added.

Nice to see the method documented, even though it might seem somewhat obvious to some.


52-64: LGTM! The update flow is well-structured.

The validation enforcement with raise_exception=True and the proper use of set_password() + save() correctly implement the password change logic. The explicit old password check with clear error messaging is a nice touch.

The static analysis hints about unused args and kwargs parameters can be safely ignored—they're standard parameters for overriding DRF's UpdateAPIView.update() method.

@19vip
Copy link
Author

19vip commented Dec 26, 2025

Hi @ohcnetwork/care-backend-admins,
I’ve addressed all feedback from the initial review and the automated checks.
Docstring coverage is now above the required threshold, exception chaining has been added, and the PR description follows the project template.
All tests are passing. Please let me know if any further changes are needed. Thank you!

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.

1 participant