Skip to content

Prevent last admin from deleting themselves#792

Merged
seapagan merged 8 commits intomainfrom
feature/admin-deletion-protection
Dec 29, 2025
Merged

Prevent last admin from deleting themselves#792
seapagan merged 8 commits intomainfrom
feature/admin-deletion-protection

Conversation

@seapagan
Copy link
Owner

@seapagan seapagan commented Dec 29, 2025

Summary

Implements admin deletion protection to prevent the last admin user from deleting themselves, avoiding system lockout.

Changes

  • ✅ API endpoint now prevents last admin self-deletion
  • ✅ CLI command updated to use same protection logic
  • ✅ Comprehensive test coverage (integration + unit tests)
  • ✅ Documentation updated in user guide and API reference

Implementation Details

  • Added CANT_DELETE_LAST_ADMIN error message
  • Updated UserManager.delete_user() to count admins and block deletion when:
    • User being deleted is an admin
    • Only 1 admin exists in the system
    • Current user is trying to delete themselves
  • Modified CLI delete command to use UserManager.delete_user() instead of direct session manipulation
  • Regular users can always be deleted regardless of admin count
  • Admins can delete themselves when multiple admins exist

Test Coverage

  • 3 new integration tests for API endpoint
  • 3 new unit tests for manager logic
  • 1 new CLI test for admin protection
  • All existing tests updated and passing

Edge Cases Covered

  • Last admin trying to delete themselves (blocked)
  • Admin deletion when multiple admins exist (allowed)
  • Admin deleting another admin (allowed if multiple admins)
  • Admin deleting regular user (always allowed)
  • Non-admin users cannot delete (existing auth check)

seapagan and others added 2 commits December 29, 2025 08:09
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@codacy-production
Copy link

codacy-production bot commented Dec 29, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.00% (target: -1.00%) 100.00%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (40b9792) 1704 1704 100.00%
Head commit (6e04b3f) 1709 (+5) 1709 (+5) 100.00% (+0.00%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#792) 18 18 100.00%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Updates the CLI delete command to use UserManager.delete_user()
instead of direct session manipulation, ensuring consistent
admin protection between CLI and API endpoints.

Changes:
- Refactored delete command to call UserManager.delete_user()
- Added HTTPException handling for validation errors
- Updated all delete tests to mock UserManager instead of session
- Added test_delete_last_admin_blocked for admin protection
- Removed unnecessary try/except that immediately re-raised

The CLI now correctly prevents deletion of the last admin user,
matching the behavior of the API endpoint.
@seapagan seapagan force-pushed the feature/admin-deletion-protection branch from 89fd9a9 to 15ce45f Compare December 29, 2025 08:48
@seapagan seapagan self-assigned this Dec 29, 2025
@seapagan seapagan added the enhancement New feature or request label Dec 29, 2025
@seapagan seapagan requested a review from Copilot December 29, 2025 08:53
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements admin deletion protection to prevent the last admin user from deleting themselves, which would lock out the system from administrative access.

Key Changes:

  • Added logic to UserManager.delete_user() that counts admin users and blocks deletion when the user is an admin, only 1 admin exists, and the current user is deleting themselves
  • Updated API endpoint and CLI command to pass current_user_id parameter for self-deletion detection
  • Added comprehensive test coverage with 7 new tests across unit, integration, and CLI test suites

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
app/managers/user.py Added admin count check and CANT_DELETE_LAST_ADMIN error; updated delete_user() signature to accept current_user_id
app/resources/user.py Modified delete endpoint to pass request.state.user.id as current user to deletion logic
app/commands/user.py Refactored CLI delete command to use UserManager.delete_user() instead of direct session manipulation; passes user_id twice to simulate self-deletion
tests/unit/test_user_manager.py Added 3 unit tests for last admin protection scenarios and updated existing tests for new method signature
tests/integration/test_user_routes.py Added 3 integration tests verifying API endpoint behavior for admin deletion scenarios
tests/cli/test_cli_user_command.py Updated CLI delete tests to mock UserManager.delete_user() and added test for last admin protection
tests/unit/test_jwt_auth.py Updated test to use new delete_user() signature with two parameters
tests/unit/test_api_key_auth.py Updated test to use new delete_user() signature with two parameters
docs/usage/user-control.md Added warning section explaining admin deletion protection
docs/reference/api.md Documented 400 error response and admin protection behavior in delete endpoint

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

seapagan and others added 4 commits December 29, 2025 09:36
docs: clarify admin deletion protection

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Grant Ramsay <seapagan@gmail.com>
Explicitly set unique emails for all tests that create multiple users
to prevent Faker from potentially generating duplicate emails.

Fixed tests:
- 2-user creation tests (5 tests)
- Loop-based 3-user creation tests (4 tests)

This eliminates potential flakiness from unique email constraint
violations.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Remove unnecessary current_user_id parameter from delete_user.
The protection now simply prevents deletion of the last admin user,
regardless of who is performing the deletion. This is simpler, more
defensive, and works identically for both API and CLI contexts.

Changes:
- UserManager.delete_user now takes only (user_id, session)
- Removed self-deletion check - not needed
- Protection triggers when admin_count <= 1 (period)
- API endpoint no longer needs Request parameter
- CLI implementation simplified (no duplicate user_id)
- Updated all tests to match new signature
- Updated test docstrings to reflect simplified logic

This addresses the over-engineering of the self-deletion check and
provides stronger protection against accidental system lockout.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@seapagan seapagan merged commit b8ed4a1 into main Dec 29, 2025
23 checks passed
@seapagan seapagan deleted the feature/admin-deletion-protection branch December 29, 2025 10:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants