BatchMode=yes already blocked TTY prompts, but a brand-new host with no
known_hosts entry failed outright on first connect since ssh had no way
to ask for acceptance. Add StrictHostKeyChecking=accept-new (TOFU, still
hard-fails on a changed known host) plus LogLevel=ERROR to keep the
resulting "permanently added" notice out of profile logs.
Also force ControlMaster=no/ControlPath=none and ClearAllForwardings=yes
so a user's own ~/.ssh/config can't make porthole's spawned ssh share a
multiplexed connection or apply extra forwards - the supervisor's
process-based tracking assumes one spawned ssh exclusively owns one
tunnel. ServerAliveCountMax=3 makes dead-connection detection time
deterministic against the profile's keepalive, and -T is explicit
no-pty insurance alongside the existing -N. IdentitiesOnly=yes is added
whenever a profile sets an identity file, avoiding auth-failure lockouts
from also offering agent/default keys.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up to the previous comment pass, which covered source comments -
this one is specifically the doc comments that render as --help output:
- Dropped "Deep-dive" (casual/jargon) from status's description in favor
of the imperative-verb pattern every other command description uses
(Save/Start/Stop/Update/List/Delete/Generate).
- Replaced the "SIGTERM + wait" shorthand in close --force's help with a
plain sentence - "+" as an ad-hoc conjunction doesn't belong in
user-facing text.
- Unified all positional NAME descriptions to the same "Name of the
profile to <verb>" shape (add's was "Name for the new profile",
breaking the pattern); open's picked up the same parenthetical-clarifier
convention already used elsewhere ("(ignored with --all)", matching
"(doesn't open it)", "(SOCKS proxy)").
- Trimmed the redundant "SSH" prefix from --via's description (the whole
tool is SSH-specific, so it added nothing); kept it on --port's, where
it disambiguates the SSH connection port from the forward's own port
numbers.
- Fixed the Cli struct's doc comment to match what --command(about)
actually renders (Cargo.toml's description, not the doc comment
verbatim) - it carried a stale "porthole - " prefix that never showed.
- -l/-r/-d now show their actual grammar as the clap value name
(<[BIND:]PORT:HOST:PORT>, <[BIND:]PORT>) instead of a generic <SPEC>,
matching vmic's convention of showing real syntax in --help. The
grammar is no longer also repeated in the flag's help text, since the
value name already carries it.
- --via changes from a single comma-separated flag to a repeatable one
(Vec<String> + value_delimiter = ','), so both `--via a --via b` and
`--via a,b` work and can be mixed. commands/mod.rs's edits_from_mapping
no longer needs to split the string itself - clap does it.
- Trimmed CLI help text that restated grammar/rationale already covered
by the value name or by --via being required.
- Normalized code comments for tone/format consistency: dropped
cross-references to vmic's own internals as justification (this
codebase should read as self-contained), removed markdown-style
*emphasis* asterisks that don't render in plain comments, tightened
several run-on sentences into plain declarative ones, and fixed one
comment in wipe.rs that inaccurately described close_instance's force
path (it sends SIGKILL, not SIGTERM).
- spec/porthole-spec.md's --via row updated to document the repeatable
form alongside comma-separated.
Cargo.toml/Cargo.lock/atomic.rs also carry an external toml crate bump
and formatting pass picked up from the working tree.
Ports vmic's print_full_help (main.rs) verbatim in spirit: one line per
subcommand with its positional args inline, an indented per-flag block
underneath with globally-aligned columns, a separate Aliases section, and
NO_COLOR-aware coloring - so `porthole`/`porthole -h`/`porthole help` show
every subcommand's flags without drilling into each one's own --help,
matching vmic's actual rendered output exactly in structure.
Also shortened --via's clap value_name from the full grammar
([user@]host[:port][,...]) to HOPS - the long form blew out the column
alignment for every other flag's help text; the full grammar is still in
the flag's help string itself.
Dropped vmic's MULTI_CHAR_ALIASES workaround (for short flags like -sv
that clap can't express natively) since porthole has no multi-char short
flags today - add it back if one shows up.
Full CLI per spec v0.2 - add/open/close/edit/status/list/remove/wipe/
completions, plus a hidden `__supervise` subcommand that IS the
supervisor process.
- profile.rs: TOML-backed profiles at ~/.config/porthole/profiles/,
validated -l/-r/-d mapping + --via grammar, atomic writes.
- instance.rs: JSON runtime state at ~/.local/state/porthole/, an
flock-based lock file that's the source of truth for "is this open"
(survives a crash/kill -9 without stale-lock cleanup), pid liveness
checked against /proc rather than trusted from disk.
- supervisor.rs: the __supervise loop - spawns ssh, traps SIGTERM/SIGINT
into a flag (rather than inferring intent from ssh's exit status),
classifies failures as fatal/known-transient/unrecognized, backs off
with a stability-reset, rotates its log.
- ssh.rs: builds the ssh invocation, including splitting --via into a
-J jump chain plus the mandatory positional target.
- open.rs: the detach/re-exec dance (setsid via pre_exec) and a bounded
wait for the supervisor to reach Up/Error before open returns, so an
immediate failure surfaces as a non-zero exit instead of a false
"opened" - this took a real bug fix during smoke testing, since the
instance file's initial state (Reconnecting, meaning "attempt in
flight") was indistinguishable from "already failed once" by state
alone.
- close.rs: SIGTERM+wait, or SIGKILL the whole process group with
--force so ssh can't be left orphaned.
Smoke-tested against invalid/unreachable hosts (no real infrastructure
touched): CLI surface, validation errors, add/edit/list/status/remove,
the reconnect/backoff loop with live state transitions, close mid-retry,
edit-while-running's warning, open --all, and wipe. cargo test: 14/14.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>