Big-Link-Man/docs/stories/story-1.5-cli-user-manageme...

441 lines
14 KiB
Markdown

# Story 1.5: Command-Line User Management - COMPLETED
## Overview
Implemented comprehensive CLI commands for user management with admin authentication, including commands to add, delete, and list users through a command-line interface.
## Story Details
**As an Admin**, I want command-line tools to add and remove users, so that I can manage system access for the MVP.
## Acceptance Criteria - ALL MET
### 1. CLI Command to Create Users
**Status:** COMPLETE
A CLI command exists to create new users with specified username, password, and role:
- Command: `add-user`
- Options: `--username`, `--password`, `--role`, `--admin-user`, `--admin-password`
- Roles: Admin or User (case-sensitive)
- Password confirmation prompt built-in
- Returns success message with created user details
### 2. CLI Command to Delete Users
**Status:** COMPLETE
A CLI command exists to delete users by their username:
- Command: `delete-user`
- Options: `--username`, `--admin-user`, `--admin-password`
- Safety confirmation prompt ("Are you sure?")
- Prevents admin from deleting their own account
- Returns success message after deletion
### 3. Commands Require Admin Authentication
**Status:** COMPLETE
All user management commands require admin authentication:
- Admin credentials prompted if not provided via options
- Authentication verified against database with hashed passwords
- Non-admin users cannot execute user management commands
- Returns appropriate error messages for auth failures
### 4. Appropriate Feedback Provided
**Status:** COMPLETE
Commands provide clear feedback to the console:
- Success messages for successful operations
- Error messages for failures (auth, validation, duplicates)
- User-friendly prompts for required inputs
- Proper exit codes (0 for success, 1 for failure)
## Implementation Details
### Files Created/Modified
#### 1. `src/cli/commands.py` - UPDATED
```python
New Functions:
- authenticate_admin(username, password) -> Optional[User]
- Authenticates user and verifies admin role
- Returns User object if admin, None otherwise
- prompt_admin_credentials() -> tuple[str, str]
- Prompts for admin username and password
- Hides password input for security
New Commands:
- add-user: Create a new user
- delete-user: Delete an existing user
- list-users: List all users (bonus command)
```
**Key Features:**
- HTTP Basic Authentication against database
- Role-based access control (Admin only)
- Interactive prompts for missing credentials
- Comprehensive error handling
- Session management with proper cleanup
#### 2. `tests/unit/test_cli_commands.py` - NEW
```python
Test coverage for CLI commands:
- TestAuthenticateAdmin: 3 tests
- TestAddUserCommand: 4 tests
- TestDeleteUserCommand: 4 tests
- TestListUsersCommand: 3 tests
- TestExistingCommands: 3 tests
Total: 17 unit tests
```
**Test Coverage:**
- Mocked dependencies for isolated testing
- Authentication flow testing
- Role-based access control verification
- Error handling scenarios
- All edge cases covered
#### 3. `tests/integration/test_cli_integration.py` - NEW
```python
Integration tests with real database:
- TestAddUserIntegration: 5 tests
- TestDeleteUserIntegration: 4 tests
- TestListUsersIntegration: 4 tests
- TestUserManagementWorkflow: 2 tests
- TestExistingCommandsIntegration: 3 tests
Total: 18 integration tests
```
**Integration Features:**
- Real database interactions
- Full authentication flow
- Multi-user scenarios
- Complete lifecycle testing
- Security verification
#### 4. `tests/conftest.py` - UPDATED
Added shared `db_session` fixture for all integration tests:
- Creates in-memory SQLite database
- Initializes schema automatically
- Provides clean session per test
- Automatic cleanup after tests
### Commands
#### Add User Command
**Usage:**
```bash
# Interactive mode (prompts for all inputs)
python main.py add-user
# With credentials provided
python main.py add-user --username newuser --password pass123 --role User --admin-user admin --admin-password adminpass
# Mixed mode (prompts for missing inputs)
python main.py add-user --username newuser --role User
```
**Options:**
- `--username`: Username for the new user (required)
- `--password`: Password for the new user (required, with confirmation)
- `--role`: Role for the new user - Admin or User (required)
- `--admin-user`: Admin username for authentication (optional, prompts if missing)
- `--admin-password`: Admin password for authentication (optional, prompts if missing)
**Examples:**
```bash
# Create a regular user
python main.py add-user --username john --password secure123 --role User --admin-user admin --admin-password adminpass
# Output: Success: User 'john' created with role 'User'
# Create an admin user
python main.py add-user --username newadmin --password admin456 --role Admin --admin-user admin --admin-password adminpass
# Output: Success: User 'newadmin' created with role 'Admin'
```
**Error Cases:**
- Duplicate username: "Error: User with username 'X' already exists"
- Invalid admin credentials: "Error: Authentication failed or insufficient permissions"
- Invalid role: Must be 'Admin' or 'User'
#### Delete User Command
**Usage:**
```bash
# Interactive mode
python main.py delete-user
# With credentials provided
python main.py delete-user --username olduser --admin-user admin --admin-password adminpass --yes
# Prompts for confirmation
python main.py delete-user --username olduser
```
**Options:**
- `--username`: Username to delete (required)
- `--admin-user`: Admin username for authentication (optional, prompts if missing)
- `--admin-password`: Admin password for authentication (optional, prompts if missing)
- `--yes`: Skip confirmation prompt
**Examples:**
```bash
# Delete a user
python main.py delete-user --username john --admin-user admin --admin-password adminpass --yes
# Output: Success: User 'john' has been deleted
# Try to delete non-existent user
python main.py delete-user --username nonexistent --admin-user admin --admin-password adminpass --yes
# Output: Error: User 'nonexistent' not found
```
**Safety Features:**
- Confirmation prompt: "Are you sure you want to delete this user?"
- Cannot delete own account: "Error: Cannot delete your own account"
- User must exist: "Error: User 'X' not found"
#### List Users Command (Bonus)
**Usage:**
```bash
# List all users
python main.py list-users --admin-user admin --admin-password adminpass
```
**Options:**
- `--admin-user`: Admin username for authentication (optional, prompts if missing)
- `--admin-password`: Admin password for authentication (optional, prompts if missing)
**Example Output:**
```
Total users: 3
------------------------------------------------------------
ID Username Role Created
------------------------------------------------------------
1 admin Admin 2024-01-15 10:30:45
2 john User 2024-01-15 14:22:10
3 jane User 2024-01-15 15:45:33
------------------------------------------------------------
```
### Authentication Flow
1. User invokes command with or without admin credentials
2. If credentials not provided, system prompts for them
3. `authenticate_admin()` validates credentials:
- Creates database session
- Retrieves user by username
- Verifies password using bcrypt
- Checks user has Admin role
4. On success: Command executes with new database session
5. On failure: Error message displayed, command aborts
### Security Features
1. **Password Hashing**: All passwords hashed with bcrypt before storage
2. **Hidden Input**: Password prompts hide input from console
3. **Confirmation Prompts**: Password confirmation on creation, deletion confirmation
4. **Role-Based Access**: Only Admin role can manage users
5. **Self-Protection**: Admins cannot delete their own accounts
6. **Secure Sessions**: Database sessions properly closed after operations
7. **Clear Error Messages**: Generic errors prevent information leakage
### Test Coverage
#### Unit Tests (17 tests, all passing)
```bash
# Run unit tests
.venv/Scripts/python -m pytest tests/unit/test_cli_commands.py -v
Test Results:
- test_authenticate_admin_success: PASSED
- test_authenticate_admin_not_admin_role: PASSED
- test_authenticate_admin_invalid_credentials: PASSED
- test_add_user_success_with_admin_credentials: PASSED
- test_add_user_authentication_fails: PASSED
- test_add_user_duplicate_username: PASSED
- test_add_user_prompts_for_credentials: PASSED
- test_delete_user_success: PASSED
- test_delete_user_not_found: PASSED
- test_delete_user_cannot_delete_self: PASSED
- test_delete_user_authentication_fails: PASSED
- test_list_users_success: PASSED
- test_list_users_empty: PASSED
- test_list_users_authentication_fails: PASSED
- test_config_command_success: PASSED
- test_health_command_success: PASSED
- test_models_command_success: PASSED
```
#### Integration Tests (18 tests, all passing)
```bash
# Run integration tests
.venv/Scripts/python -m pytest tests/integration/test_cli_integration.py -v
Test Results:
- test_add_user_with_admin_auth: PASSED
- test_add_admin_user: PASSED
- test_add_user_with_duplicate_username: PASSED
- test_add_user_with_invalid_admin_password: PASSED
- test_add_user_with_regular_user_auth_fails: PASSED
- test_delete_user_success: PASSED
- test_delete_user_not_found: PASSED
- test_delete_own_account_fails: PASSED
- test_delete_user_with_regular_user_fails: PASSED
- test_list_users_with_admin: PASSED
- test_list_multiple_users: PASSED
- test_list_users_with_regular_user_fails: PASSED
- test_list_users_shows_creation_date: PASSED
- test_complete_user_lifecycle: PASSED
- test_multiple_admins_can_manage_users: PASSED
- test_config_command_integration: PASSED
- test_health_command_integration: PASSED
- test_models_command_integration: PASSED
```
### Testing Commands
```bash
# Run all CLI tests
.venv/Scripts/python -m pytest tests/unit/test_cli_commands.py tests/integration/test_cli_integration.py -v
# Run unit tests only
.venv/Scripts/python -m pytest tests/unit/test_cli_commands.py -v
# Run integration tests only
.venv/Scripts/python -m pytest tests/integration/test_cli_integration.py -v
# Run with coverage
.venv/Scripts/python -m pytest tests/unit/test_cli_commands.py tests/integration/test_cli_integration.py --cov=src/cli --cov-report=html
```
## Dependencies
- `click==8.1.7` - Command-line interface framework
- `sqlalchemy==2.0.23` - Database ORM
- `passlib[bcrypt]==1.7.4` - Password hashing
- `bcrypt==4.0.1` - Bcrypt implementation
- `pytest==8.4.2` - Testing framework
- `pytest-mock==3.15.1` - Mocking support for tests
## Next Steps
This CLI user management foundation is now ready for:
- **Story 1.6**: Deployment Infrastructure Management (CLI commands for bunny.net provisioning)
- **Story 1.7**: CI/CD Pipeline Setup (automated testing in pipeline)
- **Epic 2**: Content Generation features will use user authentication
- Integration with future admin dashboard/web interface
## Usage Examples
### Typical Workflow
```bash
# 1. Initial admin creates first user
python main.py add-user
# Prompts: username, password, role, admin-user, admin-password
# 2. Admin lists all users
python main.py list-users --admin-user admin --admin-password adminpass
# 3. Admin creates content creator user
python main.py add-user \
--username content_creator \
--password secure456 \
--role User \
--admin-user admin \
--admin-password adminpass
# 4. Admin deletes old user
python main.py delete-user \
--username olduser \
--admin-user admin \
--admin-password adminpass \
--yes
# 5. Verify changes
python main.py list-users --admin-user admin --admin-password adminpass
```
### Script Usage
For automated user provisioning:
```bash
# provision-users.sh
#!/bin/bash
ADMIN_USER="admin"
ADMIN_PASS="$ADMIN_PASSWORD" # From environment variable
# Create multiple users
python main.py add-user --username user1 --password pass1 --role User --admin-user $ADMIN_USER --admin-password $ADMIN_PASS
python main.py add-user --username user2 --password pass2 --role User --admin-user $ADMIN_USER --admin-password $ADMIN_PASS
python main.py add-user --username user3 --password pass3 --role User --admin-user $ADMIN_USER --admin-password $ADMIN_PASS
echo "Users provisioned successfully"
```
## Notes
- CLI commands use the same database and authentication as the API
- Password confirmation prevents typos during user creation
- Admin authentication is required for every command execution (stateless)
- Commands are designed for both interactive and scripted use
- All operations are atomic (succeed or fail completely)
- Sessions are properly managed to prevent database locks
- The `list-users` command was added as a bonus feature for better user management
## Architecture Decisions
**Why Click?**
- Industry-standard CLI framework for Python
- Excellent support for options, prompts, and confirmations
- Built-in password hiding for security
- Easy to test with CliRunner
- Great documentation and community support
**Why Require Admin Auth Per Command?**
- Stateless design (no session management needed)
- More secure (credentials not stored)
- Works well for scripting and automation
- Simpler implementation for MVP
- Can be enhanced with session tokens later
**Why Separate Database Sessions?**
- Authentication and operations use separate sessions
- Prevents transaction conflicts
- Proper cleanup and error handling
- Follows best practices for database access
- Testable with mocking
**Why Prevent Self-Deletion?**
- Prevents accidental lockout
- Ensures at least one admin always exists
- Common security best practice
- Can be overridden with special admin tools if needed
## Completion Checklist
- [x] Add-user command implemented
- [x] Delete-user command implemented
- [x] List-users command implemented (bonus)
- [x] Admin authentication required
- [x] Interactive prompts for credentials
- [x] Password confirmation on creation
- [x] Deletion confirmation prompt
- [x] Self-deletion prevention
- [x] Proper error handling
- [x] Success/failure feedback
- [x] Unit tests written and passing (17 tests)
- [x] Integration tests written and passing (18 tests)
- [x] Shared test fixtures in conftest.py
- [x] Story documentation completed
## Bonus Features Added
- **List Users Command**: Provides visibility into existing users
- **Password Confirmation**: Built-in double-entry for passwords
- **Self-Protection**: Prevents admins from deleting themselves
- **Flexible Authentication**: Can provide credentials via options or prompts
- **Formatted Output**: Clean, table-formatted user listings
- **Comprehensive Testing**: 35 total tests covering all scenarios