fix: human-readable advisories for TLS data_dir + port-53 EACCES #48

Merged
razvandimescu merged 3 commits from fix/tls-permission-advisory into main 2026-04-09 21:27:08 +08:00
razvandimescu commented 2026-04-09 20:51:04 +08:00 (Migrated from github.com)

Summary

  • New tls::try_data_dir_advisory(&err, &dir) -> Option<String> — when TLS CA setup fails with PermissionDenied (typical first-run-without-sudo on macOS/Linux), print a multi-line diagnostic naming the data dir and offering two fixes (sudo numa install or set [server] data_dir). HTTPS proxy stays disabled gracefully; DNS resolution and plain-HTTP proxy keep working.
  • Extend port-53 match arm to also catch PermissionDenied (EACCES). Previously only AddrInUse triggered the advisory, so a fresh non-root user trying to bind a privileged port saw a raw OS error. Replaces port53_conflict_advisory + public is_port_53 with a single system_dns::try_port53_advisory(bind_addr, &err) -> Option<String> that handles both error kinds via a cause-sentence variant — no duplicated fix text.
  • Both error sites in main.rs reduce to a symmetric if let Some(advisory) = ... { eprint!(...) } pattern; TLS error classification (the downcast_ref::<io::Error>) lives inside tls.rs instead of leaking into the binary entrypoint.
  • 8 new unit tests covering every branch of both helpers (AddrInUse, PermissionDenied, non-53 ports, unrelated error kinds, malformed bind_addr, non-io errors). Total: 142 tests (was 134 on main).

Follow-up to #47.

Test plan

  • make all passes locally (clippy clean, fmt clean, 142 unit tests pass)
  • Manual on macOS as non-root: ./target/release/numa prints both advisories sequentially (TLS first, then port 53), no raw Os { code: ... } errors
  • CI green on Linux + macOS + Windows
  • tests/docker/smoke-port53.sh still passes (advisory text changed slightly: assertions for cannot bind to, numa install, bind_addr all still match)

🤖 Generated with Claude Code

## Summary - New `tls::try_data_dir_advisory(&err, &dir) -> Option<String>` — when TLS CA setup fails with `PermissionDenied` (typical first-run-without-sudo on macOS/Linux), print a multi-line diagnostic naming the data dir and offering two fixes (`sudo numa install` or set `[server] data_dir`). HTTPS proxy stays disabled gracefully; DNS resolution and plain-HTTP proxy keep working. - Extend port-53 match arm to also catch `PermissionDenied` (EACCES). Previously only `AddrInUse` triggered the advisory, so a fresh non-root user trying to bind a privileged port saw a raw OS error. Replaces `port53_conflict_advisory` + public `is_port_53` with a single `system_dns::try_port53_advisory(bind_addr, &err) -> Option<String>` that handles both error kinds via a cause-sentence variant — no duplicated fix text. - Both error sites in `main.rs` reduce to a symmetric `if let Some(advisory) = ... { eprint!(...) }` pattern; TLS error classification (the `downcast_ref::<io::Error>`) lives inside `tls.rs` instead of leaking into the binary entrypoint. - 8 new unit tests covering every branch of both helpers (AddrInUse, PermissionDenied, non-53 ports, unrelated error kinds, malformed bind_addr, non-io errors). Total: 142 tests (was 134 on `main`). Follow-up to #47. ## Test plan - [x] `make all` passes locally (clippy clean, fmt clean, 142 unit tests pass) - [x] Manual on macOS as non-root: `./target/release/numa` prints both advisories sequentially (TLS first, then port 53), no raw `Os { code: ... }` errors - [x] CI green on Linux + macOS + Windows - [x] `tests/docker/smoke-port53.sh` still passes (advisory text changed slightly: assertions for `cannot bind to`, `numa install`, `bind_addr` all still match) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.