- 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.
4 KiB
Contributing
Thank you for improving hosts. Because the application modifies /etc/hosts
with elevated privileges, correctness and honest user-facing behavior take
priority over feature breadth.
Use the Forgejo issue tracker to report bugs or coordinate consequential changes.
Development setup
The project requires Python 3.13 or newer and uv:
git clone https://git.s1q.dev/phg/hosts.git
cd hosts
uv sync
uv run hosts
uv run hosts starts the real application and reads /etc/hosts. Stay in
Read-only Mode unless you deliberately intend to exercise privileged behavior
on your machine. Automated tests must use mocks and temporary files instead.
Code boundaries
src/hosts/core/owns Host Entries, parsing and serialization, configuration, DNS resolution, undo/redo commands, and privileged file operations.src/hosts/tui/owns the Textual application, handlers, modals, widgets, keybindings, and styles.tests/mirrors both layers and isolates operating-system interactions.
Keep domain and system logic out of Textual widgets. Route privileged writes
through HostsManager; UI actions should coordinate services and render their
results.
Core code that is not reachable through the TUI is not yet a supported product feature. Do not advertise it in user-facing documentation until users can actually invoke it.
Domain language and decisions
Read CONTEXT.md before naming user-visible concepts. Use its canonical terms in the interface, documentation, issues, and tests where practical.
Read the relevant architecture decision record before changing established contracts:
- ADR 0001 covers Privileged Mode, sudo handling, system-file writes, and Pre-edit Backups.
- ADR 0002 covers parsing, serialization, comment placement, and formatting preservation.
Add an ADR only for a consequential, surprising trade-off that would be expensive to reverse. Keep planned work in Forgejo issues rather than evergreen repository documents.
Safety contracts
- The application starts in Read-only Mode.
- Mutating actions require Privileged Mode, and a Pre-edit Backup must exist before writes are enabled.
- Default Entries are protected from mutation and must remain first when file order changes.
- All privileged writes go through
HostsManager. - Serialization is semantic and normalized, not byte-preserving.
- Tests never read or write the real
/etc/hosts, invoke realsudo, or depend on live DNS.
Mock subprocess and resolver boundaries and inject a temporary Hosts File path. Treat any test capable of touching the real system file as a defect.
Make and validate a change
Run the narrowest relevant test while developing. Examples:
uv run pytest tests/test_parser.py
uv run pytest tests/test_manager.py
uv run pytest tests/test_main.py
Before handing off any change, run the complete validation suite:
uv run pytest
uv run ruff check .
uv run ruff format --check .
Apply formatting with:
uv run ruff format .
Add or update tests for changed behavior. Test user-reachable workflows at the TUI boundary as well as isolated core behavior when both layers participate.
Keep documentation accurate
Documentation is part of the behavior contract:
- Update README.md when installation, major reachable features, maturity, or prominent safety limitations change.
- Update the user guide when workflows, shortcuts, persistence, recovery, configuration, or troubleshooting change.
- Update CONTEXT.md when the canonical domain language changes; keep it a glossary rather than an architecture guide or progress log.
- Update ADR 0002 and the README if serialization stops being normalized or becomes byte-preserving.
Describe only current, reachable behavior in user-facing documentation. Record future work in an issue instead of presenting it as an available feature.