git clone https://github.com/shcherbak-ai/tethered.git
cd tethered
uv sync
uv run pre-commit install --hook-type pre-commit --hook-type commit-msgThe default branch is dev. All pull requests should target dev.
The main branch is for releases only.
feature-branch → dev (PR) → main (release merge)
uv run pytest tests/ -vWith coverage:
uv run pytest tests/ -v --covPre-commit hooks run all checks automatically on every commit, but you can also run them manually:
uv run pre-commit run --all-filesIndividual tools:
uv run ruff check . # lint
uv run ruff check --fix . # lint with auto-fix
uv run ruff format . # format
uv run pyright src/ # type check
uv run interrogate src/ -v # docstring coverage
uv run bandit -c pyproject.toml -r src/ # security scanThis project uses Conventional Commits enforced by commitizen. The commit-msg hook validates every commit message automatically. Run uv run cz commit for an interactive session that guides you through the format.
src/tethered/
__init__.py # Public API: activate(), deactivate(), EgressBlocked
_policy.py # AllowPolicy — pattern parsing and matching (pure logic)
_core.py # Audit hook, state management, IP-to-hostname resolution
tests/
test_policy.py # Unit tests for AllowPolicy (no network)
test_core.py # Integration tests with real sockets
Use only reserved, unroutable ranges for IP addresses in tests:
| Range | Name | RFC |
|---|---|---|
192.0.2.0/24 |
TEST-NET-1 | RFC 5737 |
198.51.100.0/24 |
TEST-NET-2 | RFC 5737 |
203.0.113.0/24 |
TEST-NET-3 | RFC 5737 |
2001:db8::/32 |
Documentation IPv6 | RFC 3849 |
127.0.0.0/8, ::1 |
Loopback | — |
Never use real, routable IPs (e.g., 8.8.8.8, 93.184.215.14). Even in "allow" tests, TEST-NET addresses ensure no packets reach real servers.
Some integration tests need real DNS resolution to verify that allowed hostnames pass through correctly. Use dns.google or localhost for this. These are the only real hostnames permitted in tests — they perform only a harmless DNS lookup, no application-level connection is made.
Never use hostnames that could trigger unexpected connections to services with side effects (e.g., API endpoints, webhook URLs).
- Zero runtime dependencies — stdlib only.
from __future__ import annotationsin all modules.- Private modules prefixed with
_. - Type hints on all public functions.
- Python 3.10+ only — no syntax from 3.12+ (
typestatement) or 3.11+ (except*).
- Policy tests (
test_policy.py): Pure logic, no audit hooks, no network. Bulk of coverage lives here. - Integration tests (
test_core.py): Use real sockets. The_cleanupautouse fixture calls_reset_state()after each test. - Tests must not depend on external network availability for correctness.
- Blocked connection tests verify
EgressBlockedis raised before any packet leaves the machine.