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

14 KiB

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

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

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

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:

# 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:

# 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:

# 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:

# 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:

# 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)

# 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)

# 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

# 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

# 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:

# 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

  • Add-user command implemented
  • Delete-user command implemented
  • List-users command implemented (bonus)
  • Admin authentication required
  • Interactive prompts for credentials
  • Password confirmation on creation
  • Deletion confirmation prompt
  • Self-deletion prevention
  • Proper error handling
  • Success/failure feedback
  • Unit tests written and passing (17 tests)
  • Integration tests written and passing (18 tests)
  • Shared test fixtures in conftest.py
  • 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