check_connectivity now runs a two-layer short-circuit probe:
Layer 1: TCP connect to (local_host, local_port) to confirm the
backend service (e.g. Gitea, Next.js) is actually listening.
Layer 2: original SSH auth probe (unchanged).
This fixes the common false-positive where check returned OK while the
tunneled backend was down. Unlike the previously removed _is_port_in_use
bind check (commit 4c9cd00), this uses connect() with correct semantics:
the forward target SHOULD be listening, not free.
The `_is_port_in_use` bind check was wrong for `-R` tunnels: local_port is
the forward target (e.g. a Docker container), so it should be listening,
not free. Drop the check — autossh doesn't require the target to be
reachable at startup.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Exercises the complete PID file lifecycle end-to-end using a real subprocess
with a fake autossh (sleep 60 script), covering start, stop, status, stale PID
cleanup, restart, and idempotency scenarios.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements build_autossh_cmd, start_tunnel, and stop_tunnel in process.py.
Adds _reap() helper to handle zombie processes in test environments where
the parent process is long-lived (SIGKILL leaves zombies unless waitpid is called).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Created .gitignore with standard Python patterns
- Removed committed __pycache__/__init__.cpython-314.pyc from git tracking
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>