Refactor test cases for improved readability and consistency

- Updated test_dns.py to enhance mock function definitions and improve spacing for better readability.
- Modified test_filters.py to streamline assertions and ensure consistent formatting across test cases.
- Cleaned up test_import_export.py by organizing imports and ensuring consistent formatting in CSV and JSON tests.
- Improved test_main.py by refining mock setups and ensuring consistent error handling in assertions.
This commit is contained in:
Philip Henning 2026-09-03 12:47:11 +02:00
parent 0710d10fac
commit 7872991e0b
42 changed files with 2376 additions and 2735 deletions

346
README.md
View file

@ -1,277 +1,115 @@
# hosts - /etc/hosts Manager
# hosts
A modern Python TUI (Text User Interface) application for managing your system's `/etc/hosts` file with ease and safety.
A keyboard-first terminal application for inspecting and editing `/etc/hosts`
on macOS and Linux.
## Overview
> [!WARNING]
> `hosts` is alpha software. It can replace a system file using `sudo`, and
> several recovery and persistence workflows still have known limitations.
> Read the [user guide](docs/user-guide.md) before entering Privileged Mode.
The `hosts` application provides a powerful, user-friendly terminal interface for viewing, editing, and managing your `/etc/hosts` file. It eliminates the need for manual text editing while providing advanced features like DNS resolution, entry validation, and comprehensive backup capabilities.
![The hosts terminal interface](./images/user_interface.png)
## Features
## What it does
### 🔍 **Read-Only Mode (Default)**
- **Two-pane interface**: List view with detailed entry information
- **Smart parsing**: Handles all real-world hosts file formats
- **Sorting capabilities**: Sort by IP address or hostname
- **Filtering options**: Hide/show system default entries
- **Search functionality**: Find entries by hostname, IP, or comment
- **Configuration management**: Persistent settings with modal interface
- **Live reload**: Automatically refresh when hosts file changes
- Browses, searches, and sorts active and inactive Host Entries.
- Hides or shows protected localhost and broadcasthost Default Entries.
- Adds, edits, deletes, activates, deactivates, and reorders Host Entries.
- Creates DNS Entries and manually refreshes their resolved IP addresses.
- Gates every `/etc/hosts` mutation behind an explicit Privileged Mode.
- Creates a timestamped Pre-edit Backup before Privileged Mode begins.
- Supports undo and redo during the current Privileged Mode session.
### ✏️ **Edit Mode (Permission-Protected)**
- **Safe editing**: Automatic backups before any modifications
- **Entry management**: Add, delete, and modify host entries
- **Activation control**: Toggle entries active/inactive
- **Reordering**: Move entries up/down with keyboard shortcuts
- **Undo/Redo system**: Full operation history with Ctrl+Z/Ctrl+Y
- **Atomic operations**: Safe file writing with rollback capability
- **Permission management**: Secure sudo handling for system file access
The application starts in Read-only Mode. Default Entries cannot be edited,
deleted, activated, deactivated, or moved.
### 🛡️ **Safety & Reliability**
- **Automatic backups**: Timestamped backups before modifications
- **Change detection**: Track modifications with save confirmation
- **Input validation**: Comprehensive IP and hostname validation
- **Error handling**: Graceful error recovery with user feedback
- **File integrity**: Preserve comments and formatting
## Requirements
## Installation
- macOS or Linux with `/etc/hosts` and `sudo`
- Python 3.13 or newer
- [uv](https://docs.astral.sh/uv/)
### Prerequisites
- Python 3.13 or higher
- [uv](https://docs.astral.sh/uv/) package manager
The project is designed for macOS and Linux, but does not yet publish a tested
platform matrix.
## Run
The normal user entry point runs the current revision from the canonical
Forgejo repository:
### Run with uv
```bash
uvx git+https://git.s1q.dev/phg/hosts.git
```
### Setup alias
> [!CAUTION]
> This command follows the repository's default branch because the project does
> not yet publish versioned releases. Review the current project state and known
> limitations before granting sudo access.
Press `Ctrl+E` to enter Privileged Mode. The application uses an existing sudo
authorization or asks for your password, then creates a Pre-edit Backup before
enabling changes.
Start with the [user guide](docs/user-guide.md) for the complete workflow,
including persistence behavior and manual recovery.
## Essential keys
| Key | Action |
| --- | --- |
| `Up` / `Down` | Select a Host Entry |
| `Ctrl+E` | Enter or leave Privileged Mode |
| `n` | Add a Host Entry |
| `e` | Open the selected Host Entry in the Entry Editor |
| `d` | Delete the selected Host Entry |
| `Space` | Activate or deactivate the selected Host Entry |
| `Ctrl+S` | Save the current in-memory state |
| `?` | Show help |
| `q` or `Ctrl+C` | Quit |
Mutating keys work only in Privileged Mode. See the
[complete key reference](docs/user-guide.md#key-reference) for navigation,
sorting, DNS refresh, movement, undo, and redo.
## Safety and known limitations
- Most successful mutations save immediately, but undo and redo currently
change only the in-memory state until another save occurs.
- Reloading discards unsaved in-memory state.
- Sorting currently reorders the in-memory model; a later save can write that
order to `/etc/hosts`. Treat sorting as unsafe before another mutation.
- A failed save can leave the interface changed while `/etc/hosts` remains
unchanged.
- Pre-edit Backups are not listed or restored by the TUI and have no retention
management. Manual recovery is documented in the user guide.
- Leaving Privileged Mode currently invalidates the user's cached sudo
timestamp. This is [tracked for removal](https://git.s1q.dev/phg/hosts/issues/4).
- Serialization preserves Host Entries and comments semantically, but
normalizes spacing, comment placement, and blank lines. It is not a
byte-for-byte round trip.
Read [Persistence and recovery](docs/user-guide.md#persistence-and-recovery)
before making system-file changes.
## Develop and contribute
Clone the repository for development:
```bash
# Install uv if not already installed
echo "alias hosts=\"uvx git+https://git.s1q.dev/phg/hosts.git\"" >> ~/.zshrc
```
## Usage
### Basic Usage
```bash
# Launch the application
uvx git+https://git.s1q.dev/phg/hosts.git
# Or if you've setup the alias
hosts
```
### Interface Overview
![User Interface](./images/user_interface.png)
### Keyboard Shortcuts
#### Navigation
- `↑/↓`: Navigate entries
- `Home/End`: Go to first/last entry
- `Page Up/Down`: Navigate by page
#### View Operations
- `Ctrl+e`: Toggle between Read-only and Edit mode
- `Ctrl+r`: Reload hosts file
- `i`: Sort by IP address
- `h`: Sort by hostname
- `c`: Open configuration modal
- `q` or `Ctrl+C`: Quit application
#### Edit Mode (requires sudo)
- `e`: Toggle Entry edit mode
- `Space`: Toggle entry active/inactive
- `Shift+↑/↓`: Move entry up/down
- `n`: Add new entry
- `d`: Delete selected entry
- `r`: Update the current select DNS based Entry
- `Shift+r`: Update all DNS based Entries
- `Ctrl+z`: Undo last operation
- `Ctrl+y`: Redo operation
- `Ctrl+s`: Save changes
## Configuration
The application stores its configuration in `~/.config/hosts-manager/config.json`:
```json
{
"show_default_entries": true,
"default_sort_column": "ip",
"default_sort_reverse": false,
"backup_directory": "~/.config/hosts-manager/backups"
}
```
### Configuration Options
- **show_default_entries**: Show/hide system default entries (localhost, etc.)
- **default_sort_column**: Default sorting column ("ip" or "hostname")
- **default_sort_reverse**: Default sort direction
- **backup_directory**: Location for automatic backups
## Architecture
The application follows a clean, layered architecture:
```
src/hosts/
├── main.py # Application entry point
├── core/ # Business logic layer
│ ├── models.py # Data models (HostEntry, HostsFile)
│ ├── parser.py # File parsing and writing
│ ├── manager.py # Edit operations and permissions
│ ├── config.py # Configuration management
│ ├── dns.py # DNS resolution (planned)
│ ├── commands.py # Command pattern for undo/redo
│ ├── filters.py # Entry filtering and search
│ └── import_export.py # Data import/export utilities
└── tui/ # User interface layer
├── app.py # Main TUI application
├── styles.py # Visual styling
├── keybindings.py # Keyboard shortcuts
└── *.py # Modal dialogs and components
```
### Key Components
- **HostEntry**: Immutable data class representing a single hosts entry
- **HostsFile**: Container managing collections of entries with operations
- **HostsParser**: File I/O operations with atomic writing and backup
- **HostsManager**: Edit mode operations with permission management
- **HostsManagerApp**: Main TUI application with Textual framework
## Development
### Setup Development Environment
```bash
# Clone and enter directory
git clone https://github.com/yourusername/hosts.git
git clone https://git.s1q.dev/phg/hosts.git
cd hosts
# Install development dependencies
uv sync
# Run tests
uv run pytest
# Run linting
uv run ruff check
uv run ruff format
uv run hosts
```
### Testing
See [CONTRIBUTING.md](CONTRIBUTING.md) for code boundaries, safety contracts,
tests, linting, and documentation expectations. Domain language lives in
[CONTEXT.md](CONTEXT.md), and consequential design decisions live in
[`docs/adr/`](docs/adr/).
The project maintains comprehensive test coverage with 150+ tests:
```bash
# Run all tests
uv run pytest
# Run specific test modules
uv run pytest tests/test_models.py
uv run pytest tests/test_parser.py
# Run with coverage
uv run pytest --cov=src/hosts
```
### Test Coverage
- **Models**: Data validation and serialization (27 tests)
- **Parser**: File operations and parsing (15 tests)
- **Manager**: Edit operations and permissions (38 tests)
- **Configuration**: Settings persistence (22 tests)
- **TUI Components**: User interface (28 tests)
- **Commands**: Undo/redo system (43 tests)
- **Integration**: End-to-end workflows (additional tests)
### Code Quality
The project uses `ruff` for linting and formatting:
```bash
# Check code quality
uv run ruff check
# Format code
uv run ruff format
# Fix auto-fixable issues
uv run ruff check --fix
```
## Security Considerations
- **Sudo handling**: Secure elevation only when entering edit mode
- **File validation**: Comprehensive input validation and sanitization
- **Atomic operations**: Safe file writing to prevent corruption
- **Backup system**: Automatic backups before any modifications
- **Permission boundaries**: Clear separation between read and edit operations
## Troubleshooting
### Common Issues
**Permission denied when entering edit mode:**
```bash
# Ensure you can run sudo
sudo -v
# Check file permissions
ls -la /etc/hosts
```
**Configuration not saving:**
```bash
# Ensure config directory exists
mkdir -p ~/.config/hosts-manager
# Check directory permissions
ls -la ~/.config/
```
**Application won't start:**
```bash
# Check Python version
python3 --version
# Verify uv installation
uv --version
# Install dependencies
uv sync
```
## Contributing
We welcome contributions! Please see our development setup above.
### Contribution Guidelines
1. **Fork the repository** and create a feature branch
2. **Write tests** for new functionality
3. **Ensure all tests pass** with `uv run pytest`
4. **Follow code style** with `uv run ruff check`
5. **Submit a pull request** with clear description
### Future Enhancements
- **DNS Resolution**: Automatic hostname-to-IP resolution
- **Import/Export**: Support for different file formats
- **Advanced Filtering**: Complex search and filter capabilities
- **Performance Optimization**: Large file handling improvements
Report bugs and request features in the
[Forgejo issue tracker](https://git.s1q.dev/phg/hosts/issues).
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## Support
- **Issues**: Report bugs and feature requests on GitHub Issues
- **Documentation**: See the [project wiki](https://github.com/yourusername/hosts/wiki)
- **Discussions**: Join community discussions on GitHub Discussions
---
**Note**: This application modifies system files. Always ensure you have proper backups and understand the implications of hosts file changes. The application includes safety features, but system administration knowledge is recommended.
Licensed under the [MIT License](./LICENSE).